/*! 
* DevExtreme Web
* Version: 14.1.5
* Build date: Jul 16, 2014
*
* Copyright (c) 2012 - 2014 Developer Express Inc. ALL RIGHTS RESERVED
* EULA: https://www.devexpress.com/Support/EULAs/DevExtreme.xml
*/

"use strict";

if (!window.DevExpress) {
    /*! Module core, file devexpress.js */
    (function($, global, undefined) {
        (function checkjQueryVersion(version) {
            version = version.split(".");
            if (version[0] < 1 || version[0] == 1 && version[1] < 10)
                throw Error("Your version of jQuery is too old. Please upgrade jQuery to 1.10.0 or later.");
        })($.fn.jquery);
        var Class = function() {
                var wrapOverridden = function(baseProto, methodName, method) {
                        return function() {
                                var prevCallBase = this.callBase;
                                this.callBase = baseProto[methodName];
                                try {
                                    return method.apply(this, arguments)
                                }
                                finally {
                                    this.callBase = prevCallBase
                                }
                            }
                    };
                var clonePrototype = function(obj) {
                        var func = function(){};
                        func.prototype = obj.prototype;
                        return new func
                    };
                var classImpl = function(){};
                var redefine = function(members) {
                        var that = this;
                        if (!members)
                            return that;
                        var memberNames = $.map(members, function(_, k) {
                                return k
                            });
                        $.each(["toString", "toLocaleString", "valueOf"], function() {
                            if (members[this])
                                memberNames.push(this)
                        });
                        $.each(memberNames, function() {
                            var overridden = $.isFunction(that.prototype[this]) && $.isFunction(members[this]);
                            that.prototype[this] = overridden ? wrapOverridden(that.parent.prototype, this, members[this]) : members[this]
                        });
                        return that
                    };
                var include = function() {
                        var classObj = this;
                        $.each(arguments, function() {
                            if (this.ctor)
                                classObj._includedCtors.push(this.ctor);
                            for (var name in this) {
                                if (name === "ctor")
                                    continue;
                                if (name in classObj.prototype)
                                    throw Error("Member name collision: " + name);
                                classObj.prototype[name] = this[name]
                            }
                        });
                        return classObj
                    };
                var subclassOf = function(parentClass) {
                        if (this.parent === parentClass)
                            return true;
                        if (!this.parent || !this.parent.subclassOf)
                            return false;
                        return this.parent.subclassOf(parentClass)
                    };
                classImpl.inherit = function(members) {
                    var inheritor = function() {
                            if (!this || this === global || typeof this.constructor !== "function")
                                throw Error("A class must be instantiated using the 'new' keyword");
                            var instance = this,
                                ctor = instance.ctor;
                            if (ctor)
                                ctor.apply(instance, arguments);
                            $.each(instance.constructor._includedCtors, function() {
                                this.call(instance)
                            })
                        };
                    inheritor.prototype = clonePrototype(this);
                    inheritor.inherit = this.inherit;
                    inheritor.redefine = redefine;
                    inheritor.include = include;
                    inheritor.subclassOf = subclassOf;
                    inheritor.parent = this;
                    inheritor._includedCtors = this._includedCtors ? this._includedCtors.slice(0) : [];
                    inheritor.prototype.constructor = inheritor;
                    inheritor.redefine(members);
                    return inheritor
                };
                return classImpl
            }();
        function createQueue(discardPendingTasks) {
            var _tasks = [],
                _busy = false;
            function exec() {
                while (_tasks.length) {
                    _busy = true;
                    var task = _tasks.shift(),
                        result = task();
                    if (result === undefined)
                        continue;
                    if (result.then) {
                        $.when(result).always(exec);
                        return
                    }
                    throw Error("Queued task returned unexpected result");
                }
                _busy = false
            }
            function add(task, removeTaskCallback) {
                if (!discardPendingTasks)
                    _tasks.push(task);
                else {
                    if (_tasks[0] && removeTaskCallback)
                        removeTaskCallback(_tasks[0]);
                    _tasks = [task]
                }
                if (!_busy)
                    exec()
            }
            function busy() {
                return _busy
            }
            return {
                    add: add,
                    busy: busy
                }
        }
        var parseUrl = function() {
                var a = document.createElement("a"),
                    props = ["protocol", "hostname", "port", "pathname", "search", "hash"];
                var normalizePath = function(value) {
                        if (value.charAt(0) !== "/")
                            value = "/" + value;
                        return value
                    };
                return function(url) {
                        a.href = url;
                        var result = {};
                        $.each(props, function() {
                            result[this] = a[this]
                        });
                        result.pathname = normalizePath(result.pathname);
                        return result
                    }
            }();
        global.DevExpress = global.DevExpress || {};
        var enqueueAsync = function(task) {
                var deferred = $.Deferred();
                setTimeout(function() {
                    deferred.resolve(task())
                }, 60);
                return deferred
            };
        var hideTopOverlayCallback = function() {
                var callbacks = [];
                return {
                        add: function(callback) {
                            var indexOfCallback = $.inArray(callback, callbacks);
                            if (indexOfCallback === -1)
                                callbacks.push(callback)
                        },
                        remove: function(callback) {
                            var indexOfCallback = $.inArray(callback, callbacks);
                            if (indexOfCallback !== -1)
                                callbacks.splice(indexOfCallback, 1)
                        },
                        fire: function() {
                            var callback = callbacks.pop(),
                                result = !!callback;
                            if (result)
                                callback();
                            return result
                        },
                        hasCallback: function() {
                            return callbacks.length > 0
                        },
                        reset: function() {
                            callbacks = []
                        }
                    }
            }();
        var overlayTargetContainer = function() {
                var defaultTargetContainer = "body";
                return function(targetContainer) {
                        if (arguments.length)
                            defaultTargetContainer = targetContainer;
                        return defaultTargetContainer
                    }
            }();
        $.extend(global.DevExpress, {
            VERSION: "14.1.5",
            abstract: function() {
                throw Error("Not implemented");
            },
            Class: Class,
            createQueue: createQueue,
            enqueue: createQueue().add,
            enqueueAsync: enqueueAsync,
            parseUrl: parseUrl,
            hideTopOverlayCallback: hideTopOverlayCallback,
            hardwareBackButton: $.Callbacks(),
            overlayTargetContainer: overlayTargetContainer,
            rtlEnabled: false
        })
    })(jQuery, this);
    /*! Module core, file inflector.js */
    (function($, DX, undefined) {
        var _normalize = function(text) {
                if (text === undefined || text === null)
                    return "";
                return String(text)
            };
        var _ucfirst = function(text) {
                return _normalize(text).charAt(0).toUpperCase() + text.substr(1)
            };
        var _chop = function(text) {
                return _normalize(text).replace(/([a-z\d])([A-Z])/g, "$1 $2").split(/[\s_-]+/)
            };
        var dasherize = function(text) {
                return $.map(_chop(text), function(p) {
                        return p.toLowerCase()
                    }).join("-")
            };
        var underscore = function(text) {
                return dasherize(text).replace(/-/g, "_")
            };
        var camelize = function(text, upperFirst) {
                return $.map(_chop(text), function(p, i) {
                        p = p.toLowerCase();
                        if (upperFirst || i > 0)
                            p = _ucfirst(p);
                        return p
                    }).join("")
            };
        var humanize = function(text) {
                return _ucfirst(dasherize(text).replace(/-/g, " "))
            };
        var titleize = function(text) {
                return $.map(_chop(text), function(p) {
                        return _ucfirst(p.toLowerCase())
                    }).join(" ")
            };
        DX.inflector = {
            dasherize: dasherize,
            camelize: camelize,
            humanize: humanize,
            titleize: titleize,
            underscore: underscore
        }
    })(jQuery, DevExpress);
    /*! Module core, file utils.common.js */
    (function($, DX, undefined) {
        var isDefined = function(object) {
                return object !== null && object !== undefined
            };
        var isString = function(object) {
                return $.type(object) === 'string'
            };
        var isNumber = function(object) {
                return typeof object === "number" && isFinite(object) || $.isNumeric(object)
            };
        var isObject = function(object) {
                return $.type(object) === 'object'
            };
        var isArray = function(object) {
                return $.type(object) === 'array'
            };
        var isDate = function(object) {
                return $.type(object) === 'date'
            };
        var isFunction = function(object) {
                return $.type(object) === 'function'
            };
        var isExponential = function(value) {
                return isNumber(value) && value.toString().indexOf('e') !== -1
            };
        var extendFromObject = function(target, source, overrideExistingValues) {
                target = target || {};
                for (var prop in source)
                    if (source.hasOwnProperty(prop)) {
                        var value = source[prop];
                        if (!(prop in target) || overrideExistingValues)
                            target[prop] = value
                    }
                return target
            };
        var clone = function() {
                function Clone(){}
                return function(obj) {
                        Clone.prototype = obj;
                        return new Clone
                    }
            }();
        var executeAsync = function(action, context) {
                var deferred = $.Deferred(),
                    normalizedContext = context || this;
                setTimeout(function() {
                    var result = action.call(normalizedContext);
                    if (result && result.done && $.isFunction(result.done))
                        result.done(function() {
                            deferred.resolveWith(normalizedContext)
                        });
                    else
                        deferred.resolveWith(normalizedContext)
                }, 0);
                return deferred.promise()
            };
        var stringFormat = function() {
                var s = arguments[0];
                for (var i = 0; i < arguments.length - 1; i++) {
                    var reg = new RegExp("\\{" + i + "\\}", "gm");
                    s = s.replace(reg, arguments[i + 1])
                }
                return s
            };
        var findBestMatches = function(targetFilter, items, mapFn) {
                var bestMatches = [],
                    maxMatchCount = 0;
                $.each(items, function(index, itemSrc) {
                    var matchCount = 0,
                        item = mapFn ? mapFn(itemSrc) : itemSrc;
                    $.each(targetFilter, function(paramName) {
                        var value = item[paramName];
                        if (value === undefined)
                            return;
                        if (value === targetFilter[paramName]) {
                            matchCount++;
                            return
                        }
                        matchCount = -1;
                        return false
                    });
                    if (matchCount < maxMatchCount)
                        return;
                    if (matchCount > maxMatchCount) {
                        bestMatches.length = 0;
                        maxMatchCount = matchCount
                    }
                    bestMatches.push(itemSrc)
                });
                return bestMatches
            };
        var preg_quote = function(str) {
                return (str + "").replace(/([\+\*\?\\\.\[\^\]\$\(\)\{\}\>\<\|\=\!\:])/g, "\\$1")
            };
        var replaceAll = function(text, searchToken, replacementToken) {
                return text.replace(new RegExp("(" + preg_quote(searchToken) + ")", "gi"), replacementToken)
            };
        var splitPair = function(raw) {
                switch (typeof raw) {
                    case"string":
                        return raw.split(/\s+/, 2);
                    case"object":
                        return [raw.x || raw.h, raw.y || raw.v];
                    case"number":
                        return [raw];
                    default:
                        return raw
                }
            };
        var stringPairToObject = function(raw) {
                var pair = splitPair(raw),
                    x = parseInt(pair && pair[0], 10),
                    y = parseInt(pair && pair[1], 10);
                if (!isFinite(x))
                    x = 0;
                if (!isFinite(y))
                    y = x;
                return {
                        x: x,
                        y: y
                    }
            };
        function icontains(elem, text) {
            var result = false;
            $.each($(elem).contents(), function(index, content) {
                if (content.nodeType === 3 && (content.textContent || content.nodeValue || "").toLowerCase().indexOf((text || "").toLowerCase()) > -1) {
                    result = true;
                    return false
                }
            });
            return result
        }
        $.expr[":"].dxicontains = $.expr.createPseudo(function(text) {
            return function(elem) {
                    return icontains(elem, text)
                }
        });
        function deepExtendArraySafe(target, changes) {
            var prevValue,
                newValue;
            for (var name in changes) {
                prevValue = target[name];
                newValue = changes[name];
                if (target === newValue)
                    continue;
                if ($.isPlainObject(newValue) && !(newValue instanceof $.Event))
                    target[name] = deepExtendArraySafe($.isPlainObject(prevValue) ? prevValue : {}, newValue);
                else if (newValue !== undefined)
                    target[name] = newValue
            }
            return target
        }
        DX.utils = {
            isDefined: isDefined,
            isString: isString,
            isNumber: isNumber,
            isObject: isObject,
            isArray: isArray,
            isDate: isDate,
            isFunction: isFunction,
            isExponential: isExponential,
            extendFromObject: extendFromObject,
            clone: clone,
            executeAsync: executeAsync,
            stringFormat: stringFormat,
            findBestMatches: findBestMatches,
            replaceAll: replaceAll,
            deepExtendArraySafe: deepExtendArraySafe,
            splitPair: splitPair,
            stringPairToObject: stringPairToObject
        }
    })(jQuery, DevExpress);
    /*! Module core, file utils.console.js */
    (function($, DX, undefined) {
        var logger = function() {
                var console = window.console;
                function info(text) {
                    if (!console || !$.isFunction(console.info))
                        return;
                    console.info(text)
                }
                function warn(text) {
                    if (!console || !$.isFunction(console.warn))
                        return;
                    console.warn(text)
                }
                function error(text) {
                    if (!console || !$.isFunction(console.error))
                        return;
                    console.error(text)
                }
                return {
                        info: info,
                        warn: warn,
                        error: error
                    }
            }();
        var debug = function() {
                function assert(condition, message) {
                    if (!condition)
                        throw new Error(message);
                }
                function assertParam(parameter, message) {
                    assert(parameter !== null && parameter !== undefined, message)
                }
                return {
                        assert: assert,
                        assertParam: assertParam
                    }
            }();
        $.extend(DX.utils, {
            logger: logger,
            debug: debug
        })
    })(jQuery, DevExpress);
    /*! Module core, file utils.math.js */
    (function($, DX, undefined) {
        var PI = Math.PI,
            LN10 = Math.LN10;
        var cos = Math.cos,
            sin = Math.sin,
            abs = Math.abs,
            log = Math.log,
            floor = Math.floor,
            ceil = Math.ceil,
            max = Math.max,
            min = Math.min,
            isNaN = window.isNaN,
            Number = window.Number,
            NaN = window.NaN;
        var isNumber = DX.utils.isNumber,
            isExponential = DX.utils.isExponential;
        var getPrecision = function(value) {
                var stringFraction,
                    stringValue = value.toString(),
                    pointIndex = stringValue.indexOf('.'),
                    startIndex,
                    precision;
                if (isExponential(value)) {
                    precision = getDecimalOrder(value);
                    if (precision < 0)
                        return Math.abs(precision);
                    else
                        return 0
                }
                if (pointIndex !== -1) {
                    startIndex = pointIndex + 1;
                    stringFraction = stringValue.substring(startIndex, startIndex + 20);
                    return stringFraction.length
                }
                return 0
            };
        var getLog = function(value, base) {
                if (!value)
                    return 0;
                return Math.log(value) / Math.log(base)
            };
        var raiseTo = function(power, base) {
                return Math.pow(base, power)
            };
        var sign = function(value) {
                if (value === 0)
                    return 0;
                return value / abs(value)
            };
        var normalizeAngle = function(angle) {
                return (angle % 360 + 360) % 360
            };
        var convertAngleToRendererSpace = function(angle) {
                return 90 - angle
            };
        var degreesToRadians = function(value) {
                return PI * value / 180
            };
        var getCosAndSin = function(angle) {
                var angleInRadians = degreesToRadians(angle);
                return {
                        cos: cos(angleInRadians),
                        sin: sin(angleInRadians)
                    }
            };
        var DECIMAL_ORDER_THRESHOLD = 1E-14;
        var getDecimalOrder = function(number) {
                var n = abs(number),
                    cn;
                if (!isNaN(n)) {
                    if (n > 0) {
                        n = log(n) / LN10;
                        cn = ceil(n);
                        return cn - n < DECIMAL_ORDER_THRESHOLD ? cn : floor(n)
                    }
                    return 0
                }
                return NaN
            };
        var getAppropriateFormat = function(start, end, count) {
                var order = max(getDecimalOrder(start), getDecimalOrder(end)),
                    precision = -getDecimalOrder(abs(end - start) / count),
                    format;
                if (!isNaN(order) && !isNaN(precision)) {
                    if (abs(order) <= 4) {
                        format = 'fixedPoint';
                        precision < 0 && (precision = 0);
                        precision > 4 && (precision = 4)
                    }
                    else {
                        format = 'exponential';
                        precision += order - 1;
                        precision > 3 && (precision = 3)
                    }
                    return {
                            format: format,
                            precision: precision
                        }
                }
                return null
            };
        var getFraction = function(value) {
                var valueString,
                    dotIndex;
                if (isNumber(value)) {
                    valueString = value.toString();
                    dotIndex = valueString.indexOf('.');
                    if (dotIndex >= 0)
                        if (isExponential(value))
                            return valueString.substr(dotIndex + 1, valueString.indexOf('e') - dotIndex - 1);
                        else {
                            valueString = value.toFixed(20);
                            return valueString.substr(dotIndex + 1, valueString.length - dotIndex + 1)
                        }
                }
                return ''
            };
        var getSignificantDigitPosition = function(value) {
                var fraction = getFraction(value),
                    i;
                if (fraction)
                    for (i = 0; i < fraction.length; i++)
                        if (fraction.charAt(i) !== '0')
                            return i + 1;
                return 0
            };
        var adjustValue = function(value) {
                var fraction = getFraction(value),
                    nextValue,
                    i;
                if (fraction)
                    for (i = 1; i <= fraction.length; i++) {
                        nextValue = roundValue(value, i);
                        if (nextValue !== 0 && fraction[i - 2] && fraction[i - 1] && fraction[i - 2] === fraction[i - 1])
                            return nextValue
                    }
                return value
            };
        var roundValue = function(value, precision) {
                if (precision > 20)
                    precision = 20;
                if (isNumber(value))
                    if (isExponential(value))
                        return Number(value.toExponential(precision));
                    else
                        return Number(value.toFixed(precision))
            };
        var applyPrecisionByMinDelta = function(min, delta, value) {
                var minPrecision = getPrecision(min),
                    deltaPrecision = getPrecision(delta);
                return roundValue(value, minPrecision < deltaPrecision ? deltaPrecision : minPrecision)
            };
        $.extend(DX.utils, {
            getLog: getLog,
            raiseTo: raiseTo,
            sign: sign,
            normalizeAngle: normalizeAngle,
            convertAngleToRendererSpace: convertAngleToRendererSpace,
            degreesToRadians: degreesToRadians,
            getCosAndSin: getCosAndSin,
            getDecimalOrder: getDecimalOrder,
            getAppropriateFormat: getAppropriateFormat,
            getFraction: getFraction,
            adjustValue: adjustValue,
            roundValue: roundValue,
            applyPrecisionByMinDelta: applyPrecisionByMinDelta,
            getSignificantDigitPosition: getSignificantDigitPosition
        });
        DX.utils.getPrecision = getPrecision
    })(jQuery, DevExpress);
    /*! Module core, file utils.date.js */
    (function($, DX, undefined) {
        var isObject = DX.utils.isObject,
            isString = DX.utils.isString,
            isDate = DX.utils.isDate;
        var dateUnitIntervals = ['millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'];
        var addSubValues = function(value1, value2, isSub) {
                return value1 + (isSub ? -1 : 1) * value2
            };
        var toMilliseconds = function(value) {
                switch (value) {
                    case'millisecond':
                        return 1;
                    case'second':
                        return toMilliseconds('millisecond') * 1000;
                    case'minute':
                        return toMilliseconds('second') * 60;
                    case'hour':
                        return toMilliseconds('minute') * 60;
                    case'day':
                        return toMilliseconds('hour') * 24;
                    case'week':
                        return toMilliseconds('day') * 7;
                    case'month':
                        return toMilliseconds('day') * 30;
                    case'quarter':
                        return toMilliseconds('month') * 3;
                    case'year':
                        return toMilliseconds('day') * 365;
                    default:
                        return 0
                }
            };
        function parseISO8601(isoString) {
            var result = new Date(0);
            var chunks = isoString.replace("Z", "").split("T"),
                date = String(chunks[0]).split("-"),
                time = String(chunks[1]).split(":");
            var year,
                month,
                day,
                hours,
                minutes,
                seconds,
                milliseconds;
            year = Number(date[0]);
            month = Number(date[1]) - 1;
            day = Number(date[2]);
            result.setUTCDate(day);
            result.setUTCMonth(month);
            result.setUTCFullYear(year);
            if (time.length) {
                hours = Number(time[0]);
                minutes = Number(time[1]);
                seconds = Number(String(time[2]).split(".")[0]);
                milliseconds = Number(String(time[2]).split(".")[1]) || 0;
                result.setUTCHours(hours);
                result.setUTCMinutes(minutes);
                result.setUTCSeconds(seconds);
                result.setUTCMilliseconds(milliseconds)
            }
            return result
        }
        function formatISO8601(date) {
            function pad(n) {
                if (n < 10)
                    return "0".concat(n);
                return String(n)
            }
            return [date.getFullYear(), "-", pad(date.getMonth() + 1), "-", pad(date.getDate()), "T", pad(date.getHours()), ":", pad(date.getMinutes()), ":", pad(date.getSeconds()), "Z"].join("")
        }
        var convertMillisecondsToDateUnits = function(value) {
                var i,
                    dateUnitCount,
                    dateUnitInterval,
                    dateUnitIntervals = ['millisecond', 'second', 'minute', 'hour', 'day', 'month', 'year'],
                    result = {};
                for (i = dateUnitIntervals.length - 1; i >= 0; i--) {
                    dateUnitInterval = dateUnitIntervals[i];
                    dateUnitCount = Math.floor(value / toMilliseconds(dateUnitInterval));
                    if (dateUnitCount > 0) {
                        result[dateUnitInterval + 's'] = dateUnitCount;
                        value -= convertDateUnitToMilliseconds(dateUnitInterval, dateUnitCount)
                    }
                }
                return result
            };
        var convertDateTickIntervalToMilliseconds = function(tickInterval) {
                var milliseconds = 0;
                if (isObject(tickInterval))
                    $.each(tickInterval, function(key, value) {
                        milliseconds += convertDateUnitToMilliseconds(key.substr(0, key.length - 1), value)
                    });
                if (isString(tickInterval))
                    milliseconds = convertDateUnitToMilliseconds(tickInterval, 1);
                return milliseconds
            };
        var convertDateUnitToMilliseconds = function(dateUnit, count) {
                return toMilliseconds(dateUnit) * count
            };
        var getDateUnitInterval = function(tickInterval) {
                var maxInterval = -1,
                    i;
                if (isString(tickInterval))
                    return tickInterval;
                if (isObject(tickInterval)) {
                    $.each(tickInterval, function(key, value) {
                        for (i = 0; i < dateUnitIntervals.length; i++)
                            if (value && (key === dateUnitIntervals[i] + 's' || key === dateUnitIntervals[i]) && maxInterval < i)
                                maxInterval = i
                    });
                    return dateUnitIntervals[maxInterval]
                }
                return ''
            };
        var correctDateWithUnitBeginning = function(date, dateInterval) {
                var dayMonth,
                    firstQuarterMonth,
                    dateUnitInterval = getDateUnitInterval(dateInterval);
                switch (dateUnitInterval) {
                    case'second':
                        date.setMilliseconds(0);
                        break;
                    case'minute':
                        date.setSeconds(0, 0);
                        break;
                    case'hour':
                        date.setMinutes(0, 0, 0);
                        break;
                    case'year':
                        date.setMonth(0);
                    case'month':
                        date.setDate(1);
                    case'day':
                        date.setHours(0, 0, 0, 0);
                        break;
                    case'week':
                        dayMonth = date.getDate();
                        if (date.getDay() !== 0)
                            dayMonth += 7 - date.getDay();
                        date.setDate(dayMonth);
                        date.setHours(0, 0, 0, 0);
                        break;
                    case'quarter':
                        firstQuarterMonth = DX.formatHelper.getFirstQuarterMonth(date.getMonth());
                        if (date.getMonth() !== firstQuarterMonth)
                            date.setMonth(firstQuarterMonth);
                        date.setDate(1);
                        date.setHours(0, 0, 0, 0);
                        break
                }
            };
        var getDatesDifferences = function(date1, date2) {
                var differences,
                    counter = 0;
                differences = {
                    year: date1.getFullYear() !== date2.getFullYear(),
                    month: date1.getMonth() !== date2.getMonth(),
                    day: date1.getDate() !== date2.getDate(),
                    hour: date1.getHours() !== date2.getHours(),
                    minute: date1.getMinutes() !== date2.getMinutes(),
                    second: date1.getSeconds() !== date2.getSeconds()
                };
                $.each(differences, function(key, value) {
                    if (value)
                        counter++
                });
                differences.count = counter;
                return differences
            };
        var addInterval = function(value, interval, isNegative) {
                var result = null,
                    intervalObject;
                if (isDate(value)) {
                    intervalObject = isString(interval) ? getDateIntervalByString(interval.toLowerCase()) : interval;
                    result = new Date(value.getTime());
                    if (intervalObject.years)
                        result.setFullYear(addSubValues(result.getFullYear(), intervalObject.years, isNegative));
                    if (intervalObject.quarters)
                        result.setMonth(addSubValues(result.getMonth(), 3 * intervalObject.quarters, isNegative));
                    if (intervalObject.months)
                        result.setMonth(addSubValues(result.getMonth(), intervalObject.months, isNegative));
                    if (intervalObject.weeks)
                        result.setDate(addSubValues(result.getDate(), 7 * intervalObject.weeks, isNegative));
                    if (intervalObject.days)
                        result.setDate(addSubValues(result.getDate(), intervalObject.days, isNegative));
                    if (intervalObject.hours)
                        result.setHours(addSubValues(result.getHours(), intervalObject.hours, isNegative));
                    if (intervalObject.minutes)
                        result.setMinutes(addSubValues(result.getMinutes(), intervalObject.minutes, isNegative));
                    if (intervalObject.seconds)
                        result.setSeconds(addSubValues(result.getSeconds(), intervalObject.seconds, isNegative));
                    if (intervalObject.milliseconds)
                        result.setMilliseconds(addSubValues(value.getMilliseconds(), intervalObject.milliseconds, isNegative))
                }
                else
                    result = addSubValues(value, interval, isNegative);
                return result
            };
        var getDateIntervalByString = function(intervalString) {
                var result = {};
                switch (intervalString) {
                    case'year':
                        result.years = 1;
                        break;
                    case'month':
                        result.months = 1;
                        break;
                    case'quarter':
                        result.months = 3;
                        break;
                    case'week':
                        result.days = 7;
                        break;
                    case'day':
                        result.days = 1;
                        break;
                    case'hour':
                        result.hours = 1;
                        break;
                    case'minute':
                        result.minutes = 1;
                        break;
                    case'second':
                        result.seconds = 1;
                        break;
                    case'millisecond':
                        result.milliseconds = 1;
                        break
                }
                return result
            };
        var sameMonthAndYear = function(date1, date2) {
                return date1 && date2 && date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth()
            };
        var getFirstMonthDate = function(date) {
                return new Date(date.getFullYear(), date.getMonth(), 1)
            };
        var dateInRange = function(date, min, max) {
                return normalizeDate(date, min, max) === date
            };
        var normalizeDate = function(date, min, max) {
                var normalizedDate = date;
                if (date < min)
                    normalizedDate = min;
                else if (date > max)
                    normalizedDate = max;
                return normalizedDate
            };
        var getPower = function(value) {
                return value.toExponential().split("e")[1]
            };
        $.extend(DX.utils, {
            dateUnitIntervals: dateUnitIntervals,
            parseIso8601Date: parseISO8601,
            formatIso8601Date: formatISO8601,
            convertMillisecondsToDateUnits: convertMillisecondsToDateUnits,
            convertDateTickIntervalToMilliseconds: convertDateTickIntervalToMilliseconds,
            convertDateUnitToMilliseconds: convertDateUnitToMilliseconds,
            getDateUnitInterval: getDateUnitInterval,
            getDatesDifferences: getDatesDifferences,
            correctDateWithUnitBeginning: correctDateWithUnitBeginning,
            addInterval: addInterval,
            getDateIntervalByString: getDateIntervalByString,
            sameMonthAndYear: sameMonthAndYear,
            getFirstMonthDate: getFirstMonthDate,
            dateInRange: dateInRange,
            normalizeDate: normalizeDate,
            getPower: getPower
        })
    })(jQuery, DevExpress);
    /*! Module core, file utils.dom.js */
    (function($, DX, undefined) {
        var IOS_APP_BAR_HEIGHT = "20px";
        var timeRedrawOnResize = 100;
        var createResizeHandler = function(callback) {
                var $window = $(window),
                    timeout;
                var debug_callback = arguments[1];
                var handler = function() {
                        var width = $window.width(),
                            height = $window.height();
                        clearTimeout(timeout);
                        timeout = setTimeout(function() {
                            $window.width() === width && $window.height() === height && callback();
                            debug_callback && debug_callback()
                        }, timeRedrawOnResize)
                    };
                handler.stop = function() {
                    clearTimeout(timeout);
                    return this
                };
                return handler
            };
        var windowResizeCallbacks = function() {
                var prevSize,
                    callbacks = $.Callbacks(),
                    jqWindow = $(window),
                    resizeEventHandlerAttached = false,
                    originalCallbacksAdd = callbacks.add,
                    originalCallbacksRemove = callbacks.remove;
                var formatSize = function() {
                        return [jqWindow.width(), jqWindow.height()].join()
                    };
                var handleResize = function() {
                        var now = formatSize();
                        if (now === prevSize)
                            return;
                        prevSize = now;
                        setTimeout(callbacks.fire)
                    };
                prevSize = formatSize();
                callbacks.add = function() {
                    var result = originalCallbacksAdd.apply(callbacks, arguments);
                    if (!resizeEventHandlerAttached && callbacks.has()) {
                        jqWindow.on("resize", handleResize);
                        resizeEventHandlerAttached = true
                    }
                    return result
                };
                callbacks.remove = function() {
                    var result = originalCallbacksRemove.apply(callbacks, arguments);
                    if (!callbacks.has() && resizeEventHandlerAttached) {
                        jqWindow.off("resize", handleResize);
                        resizeEventHandlerAttached = false
                    }
                    return result
                };
                return callbacks
            }();
        var resetActiveElement = function() {
                var activeElement = document.activeElement;
                if (activeElement && activeElement !== document.body && activeElement.blur)
                    activeElement.blur()
            };
        var createMarkupFromString = function(str) {
                var tempElement = $("<div />");
                if (window.WinJS)
                    WinJS.Utilities.setInnerHTMLUnsafe(tempElement.get(0), str);
                else
                    tempElement.append(str);
                return tempElement.contents()
            };
        var initMobileViewport = function(options) {
                options = $.extend({}, options);
                var device = DX.devices.current();
                var realDevice = DX.devices.real();
                var allowZoom = options.allowZoom,
                    allowPan = options.allowPan,
                    allowSelection = "allowSelection" in options ? options.allowSelection : device.platform == "desktop";
                DX.overlayTargetContainer(".dx-viewport");
                var metaSelector = "meta[name=viewport]";
                if (!$(metaSelector).length)
                    $("<meta />").attr("name", "viewport").appendTo("head");
                var metaVerbs = ["width=device-width"],
                    msTouchVerbs = [];
                if (allowZoom)
                    msTouchVerbs.push("pinch-zoom");
                else
                    metaVerbs.push("initial-scale=1.0", "maximum-scale=1.0, user-scalable=no");
                if (allowPan)
                    msTouchVerbs.push("pan-x", "pan-y");
                if (!allowPan && !allowZoom)
                    $("html, body").css({
                        "-ms-content-zooming": "none",
                        "-ms-user-select": "none",
                        overflow: "hidden"
                    });
                else
                    $("html").css("-ms-overflow-style", "-ms-autohiding-scrollbar");
                if (!allowSelection) {
                    if (realDevice.ios)
                        $(document).on("selectstart", function() {
                            return false
                        });
                    $(".dx-viewport").css("user-select", "none")
                }
                $(metaSelector).attr("content", metaVerbs.join());
                $("html").css("-ms-touch-action", msTouchVerbs.join(" ") || "none");
                if (DX.support.touch)
                    $(document).off(".dxInitMobileViewport").on("touchmove.dxInitMobileViewport", function(e) {
                        var count = e.originalEvent.touches.length,
                            zoomDisabled = !allowZoom && count > 1,
                            panDisabled = !allowPan && count === 1 && !e.isScrollingEvent;
                        if (zoomDisabled || panDisabled)
                            e.preventDefault()
                    });
                realDevice = DX.devices.real();
                if (realDevice.ios) {
                    var isPhoneGap = document.location.protocol === "file:";
                    if (!isPhoneGap)
                        windowResizeCallbacks.add(function() {
                            var windowWidth = $(window).width();
                            $("body").width(windowWidth)
                        });
                    else if (realDevice.version[0] > 6) {
                        $(".dx-viewport").css("position", "relative");
                        $("body").css({"box-sizing": "border-box"});
                        $("body").css("padding-top", IOS_APP_BAR_HEIGHT);
                        if (realDevice.version[0] === 7 && realDevice.version[1] < 1) {
                            var setDeviceHeight = function() {
                                    var deviceHeight = "height=device-" + (Math.abs(window.orientation) === 90 ? "width" : "height");
                                    $(metaSelector).attr("content", metaVerbs.join() + "," + deviceHeight)
                                };
                            $(window).on("orientationchange", setDeviceHeight);
                            setDeviceHeight()
                        }
                    }
                }
            };
        var triggerVisibilityChangeEvent = function(event) {
                return function(element) {
                        $(element || "body").find(".dx-visibility-change-handler").each(function() {
                            $(this).triggerHandler(event)
                        })
                    }
            };
        $.extend(DX.utils, {
            createResizeHandler: createResizeHandler,
            windowResizeCallbacks: windowResizeCallbacks,
            resetActiveElement: resetActiveElement,
            createMarkupFromString: createMarkupFromString,
            triggerShownEvent: triggerVisibilityChangeEvent("dxshown"),
            triggerHidingEvent: triggerVisibilityChangeEvent("dxhiding"),
            initMobileViewport: initMobileViewport
        });
        DX.utils.__timeRedrawOnResize = timeRedrawOnResize
    })(jQuery, DevExpress);
    /*! Module core, file utils.graphics.js */
    (function($, DX, undefined) {
        var isFunction = DX.utils.isFunction,
            iDevice = /iphone|ipad/.test(navigator.userAgent.toLowerCase());
        var getLabelConnectorCoord = function(labelBox, graphBox, centerLabel, rotated) {
                var floor = Math.floor,
                    x1,
                    x2,
                    y1,
                    y2;
                x1 = floor(labelBox.x + labelBox.width / 2);
                x2 = floor(graphBox.x + graphBox.width / 2);
                if (labelBox.y + labelBox.height < graphBox.y) {
                    y1 = centerLabel || labelBox.y + labelBox.height;
                    y2 = graphBox.y
                }
                else if (labelBox.y > graphBox.y + graphBox.height) {
                    y1 = centerLabel || labelBox.y;
                    y2 = graphBox.y + graphBox.height
                }
                else if (labelBox.x > graphBox.x + graphBox.width || labelBox.x + labelBox.width < graphBox.x)
                    if (labelBox.y - graphBox.y < graphBox.y + graphBox.height - (labelBox.y + labelBox.height)) {
                        y1 = centerLabel || labelBox.y;
                        y2 = graphBox.y
                    }
                    else {
                        y1 = centerLabel || labelBox.y + labelBox.height;
                        y2 = graphBox.y + graphBox.height
                    }
                else
                    return;
                return !rotated ? [x1, y1, x2, y2] : [y1, x1, y2, x2]
            };
        var processSeriesTemplate = function(seriesTemplate, items) {
                var customizeSeries = isFunction(seriesTemplate.customizeSeries) ? seriesTemplate.customizeSeries : $.noop,
                    nameField = seriesTemplate.nameField || 'series',
                    generatedSeries = {},
                    seriesOrder = [],
                    series;
                for (var i = 0, length = items.length; i < length; i++) {
                    var data = items[i];
                    if (nameField in data) {
                        series = generatedSeries[data[nameField]];
                        if (!series) {
                            series = generatedSeries[data[nameField]] = {
                                name: data[nameField],
                                data: []
                            };
                            seriesOrder.push(series.name)
                        }
                        series.data.push(data)
                    }
                }
                return $.map(seriesOrder, function(orderedName) {
                        var group = generatedSeries[orderedName],
                            seriesOptions = customizeSeries.call(null, group.name);
                        return $.extend(group, seriesOptions)
                    })
            };
        var getNextDefsSvgId = function() {
                var numDefsSvgElements = 1;
                return function() {
                        return 'DevExpress_' + numDefsSvgElements++
                    }
            }();
        var getRootOffset = function(renderer) {
                var node,
                    result = {
                        left: 0,
                        top: 0
                    },
                    pointTransform,
                    root = renderer.getRoot();
                if (root) {
                    node = root.element;
                    if (node.getScreenCTM && !iDevice) {
                        var ctm = node.getScreenCTM();
                        if (ctm) {
                            pointTransform = node.createSVGPoint().matrixTransform(ctm);
                            result.left = pointTransform.x + (document.body.scrollLeft || document.documentElement.scrollLeft);
                            result.top = pointTransform.y + (document.body.scrollTop || document.documentElement.scrollTop)
                        }
                        else {
                            result.left = document.body.scrollLeft || document.documentElement.scrollLeft;
                            result.top = document.body.scrollTop || document.documentElement.scrollTop
                        }
                    }
                    else
                        result = $(node).offset()
                }
                return result
            };
        $.extend(DX.utils, {
            getLabelConnectorCoord: getLabelConnectorCoord,
            processSeriesTemplate: processSeriesTemplate,
            getNextDefsSvgId: getNextDefsSvgId,
            getRootOffset: getRootOffset
        })
    })(jQuery, DevExpress);
    /*! Module core, file utils.arrays.js */
    (function($, DX, undefined) {
        var wrapToArray = function(entity) {
                return $.isArray(entity) ? entity : [entity]
            };
        var removeDublicates = function(from, what) {
                if (!$.isArray(from) || from.length === 0)
                    return [];
                if (!$.isArray(what) || what.length === 0)
                    return from.slice();
                var result = [];
                $.each(from, function(_, value) {
                    var bIndex = $.inArray(value, what);
                    if (bIndex === -1)
                        result.push(value)
                });
                return result
            };
        $.extend(DX.utils, {
            wrapToArray: wrapToArray,
            removeDublicates: removeDublicates
        })
    })(jQuery, DevExpress);
    /*! Module core, file devices.js */
    (function($, DX, undefined) {
        var KNOWN_UA_TABLE = {
                iPhone: "iPhone",
                iPhone5: "iPhone 5",
                iPad: "iPad",
                iPadMini: "iPad Mini",
                androidPhone: "Android Mobile",
                androidTablet: "Android",
                win8: "MSAppHost",
                win8Phone: "Windows Phone 8",
                msSurface: "MSIE ARM Tablet PC",
                desktop: "desktop",
                tizen: "Tizen Mobile"
            };
        var DEFAULT_DEVICE = {
                deviceType: "",
                platform: "",
                version: [],
                phone: false,
                tablet: false,
                android: false,
                ios: false,
                win8: false,
                tizen: false,
                generic: false
            };
        var GENERIC_DEVICE = $.extend(DEFAULT_DEVICE, {
                platform: "generic",
                deviceType: "desktop",
                generic: true
            });
        var uaParsers = {
                ios: function(userAgent) {
                    if (!/ip(hone|od|ad)/i.test(userAgent))
                        return;
                    var isPhone = /ip(hone|od)/i.test(userAgent);
                    var matches = userAgent.match(/os (\d+)_(\d+)_?(\d+)?/i);
                    var version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10), parseInt(matches[3] || 0, 10)] : [];
                    return {
                            deviceType: isPhone ? "phone" : "tablet",
                            platform: "ios",
                            version: version
                        }
                },
                android: function(userAgent) {
                    if (!/android|htc_|silk/i.test(userAgent))
                        return;
                    var isPhone = /mobile/i.test(userAgent);
                    var matches = userAgent.match(/android (\d+)\.(\d+)\.?(\d+)?/i);
                    var version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10), parseInt(matches[3] || 0, 10)] : [];
                    return {
                            deviceType: isPhone ? "phone" : "tablet",
                            platform: "android",
                            version: version
                        }
                },
                win8: function(userAgent) {
                    var isPhone = /windows phone/i.test(userAgent),
                        isTablet = !isPhone && /arm(.*)trident/i.test(userAgent),
                        isDesktop = !isPhone && !isTablet && /msapphost/i.test(userAgent);
                    if (!(isPhone || isTablet || isDesktop))
                        return;
                    var matches = userAgent.match(/windows phone (\d+).(\d+)/i) || userAgent.match(/windows nt (\d+).(\d+)/i),
                        version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10)] : [];
                    return {
                            deviceType: isPhone ? "phone" : isTablet ? "tablet" : "desktop",
                            platform: "win8",
                            version: version
                        }
                },
                tizen: function(userAgent) {
                    if (!/tizen/i.test(userAgent))
                        return;
                    var isPhone = /mobile/i.test(userAgent);
                    var matches = userAgent.match(/tizen (\d+)\.(\d+)/i);
                    var version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10)] : [];
                    return {
                            deviceType: isPhone ? "phone" : "tablet",
                            platform: "tizen",
                            version: version
                        }
                }
            };
        DX.Devices = DX.Class.inherit({
            ctor: function(options) {
                this._window = options && options.window || window;
                this._realDevice = this._getDevice();
                this._currentDevice = undefined;
                this._currentOrientation = undefined;
                this.orientationChanged = $.Callbacks();
                this._recalculateOrientation();
                DX.utils.windowResizeCallbacks.add($.proxy(this._recalculateOrientation, this))
            },
            current: function(deviceOrName) {
                if (deviceOrName) {
                    this._currentDevice = this._getDevice(deviceOrName);
                    DX.ui.themes.init({_autoInit: true})
                }
                else {
                    if (!this._currentDevice) {
                        deviceOrName = undefined;
                        try {
                            deviceOrName = this._getDeviceOrNameFromWindowScope()
                        }
                        catch(e) {
                            deviceOrName = this._getDeviceNameFromSessionStorage()
                        }
                        finally {
                            if (!deviceOrName)
                                deviceOrName = this._getDeviceNameFromSessionStorage()
                        }
                        this._currentDevice = this._getDevice(deviceOrName)
                    }
                    return this._currentDevice
                }
            },
            real: function() {
                var forceDevice = arguments[0];
                if ($.isPlainObject(forceDevice)) {
                    $.extend(this._realDevice, forceDevice);
                    return
                }
                return $.extend({}, this._realDevice)
            },
            orientation: function() {
                return this._currentOrientation
            },
            isRippleEmulator: function() {
                return !!this._window.tinyHippos
            },
            attachCssClasses: function(element, device) {
                var realDevice = this._realDevice,
                    $element = $(element);
                device = device || this.current();
                if (device.deviceType)
                    $element.addClass("dx-device-" + device.deviceType);
                $element.addClass("dx-device-" + realDevice.platform);
                if (realDevice.version && realDevice.version.length)
                    $element.addClass("dx-device-" + realDevice.platform + "-" + realDevice.version[0]);
                if (DX.devices.isSimulator())
                    $element.addClass("dx-simulator");
                if (DX.rtlEnabled)
                    $element.addClass("dx-rtl")
            },
            isSimulator: function() {
                try {
                    return this._isSimulator || this._window.top !== this._window.self && this._window.top["dx-force-device"] || this.isRippleEmulator()
                }
                catch(e) {
                    return false
                }
            },
            forceSimulator: function() {
                this._isSimulator = true
            },
            _getDevice: function(deviceName) {
                if (deviceName === "genericPhone")
                    deviceName = {
                        deviceType: "phone",
                        platform: "generic",
                        generic: true
                    };
                if ($.isPlainObject(deviceName))
                    return this._fromConfig(deviceName);
                else {
                    var ua;
                    if (deviceName) {
                        ua = KNOWN_UA_TABLE[deviceName];
                        if (!ua)
                            throw Error("Unknown device");
                    }
                    else
                        ua = navigator.userAgent;
                    return this._fromUA(ua)
                }
            },
            _getDeviceOrNameFromWindowScope: function() {
                var result;
                if (this._window.top["dx-force-device-object"] || this._window.top["dx-force-device"])
                    result = this._window.top["dx-force-device-object"] || this._window.top["dx-force-device"];
                return result
            },
            _getDeviceNameFromSessionStorage: function() {
                return this._window.sessionStorage && (sessionStorage.getItem("dx-force-device") || sessionStorage.getItem("dx-simulator-device"))
            },
            _fromConfig: function(config) {
                var shortcuts = {
                        phone: config.deviceType === "phone",
                        tablet: config.deviceType === "tablet",
                        android: config.platform === "android",
                        ios: config.platform === "ios",
                        win8: config.platform === "win8",
                        tizen: config.platform === "tizen",
                        generic: config.platform === "generic"
                    };
                return $.extend({}, DEFAULT_DEVICE, this._currentDevice, shortcuts, config)
            },
            _fromUA: function(ua) {
                var config;
                $.each(uaParsers, function(platform, parser) {
                    config = parser(ua);
                    return !config
                });
                if (config)
                    return this._fromConfig(config);
                return GENERIC_DEVICE
            },
            _changeOrientation: function() {
                var $window = $(this._window),
                    orientation = $window.height() > $window.width() ? "portrait" : "landscape";
                if (this._currentOrientation === orientation)
                    return;
                this._currentOrientation = orientation;
                this.orientationChanged.fire({orientation: orientation})
            },
            _recalculateOrientation: function() {
                var windowWidth = $(this._window).width();
                if (this._currentWidth === windowWidth)
                    return;
                this._currentWidth = windowWidth;
                this._changeOrientation()
            }
        });
        DX.devices = new DX.Devices
    })(jQuery, DevExpress);
    /*! Module core, file browser.js */
    (function($, DX, global, undefined) {
        var webkitRegExp = /(webkit)[ \/]([\w.]+)/,
            operaRegExp = /(opera)(?:.*version)?[ \/]([\w.]+)/,
            ieRegExp = /(msie) (\d{1,2}\.\d)/,
            ie11RegExp = /(trident).*rv:(\d{1,2}\.\d)/,
            mozillaRegExp = /(mozilla)(?:.*? rv:([\w.]+))?/;
        var ua = navigator.userAgent.toLowerCase();
        var browser = function() {
                var result = {},
                    matches = webkitRegExp.exec(ua) || operaRegExp.exec(ua) || ieRegExp.exec(ua) || ie11RegExp.exec(ua) || ua.indexOf("compatible") < 0 && mozillaRegExp.exec(ua) || [],
                    browserName = matches[1],
                    browserVersion = matches[2];
                if (browserName === "trident")
                    browserName = "msie";
                if (browserName) {
                    result[browserName] = true;
                    result.version = browserVersion
                }
                return result
            }();
        DX.browser = browser
    })(jQuery, DevExpress, this);
    /*! Module core, file support.js */
    (function($, DX, window) {
        var cssPrefixes = ["", "Webkit", "Moz", "O", "ms"],
            styles = document.createElement("dx").style;
        var transitionEndEventNames = {
                WebkitTransition: 'webkitTransitionEnd',
                MozTransition: 'transitionend',
                OTransition: 'oTransitionEnd',
                msTransition: 'MsTransitionEnd',
                transition: 'transitionend'
            };
        var styleProp = function(prop) {
                prop = DX.inflector.camelize(prop, true);
                for (var i = 0, cssPrefixesCount = cssPrefixes.length; i < cssPrefixesCount; i++) {
                    var specific = cssPrefixes[i] + prop;
                    if (specific in styles)
                        return specific
                }
            };
        var supportProp = function(prop) {
                return !!styleProp(prop)
            };
        var isNativeScrollingSupported = function(device) {
                var realDevice = DX.devices.real(),
                    realPlatform = realDevice.platform,
                    realVersion = realDevice.version,
                    isObsoleteAndroid = realVersion && realVersion[0] < 4 && realPlatform === "android",
                    isNativeScrollDevice = !isObsoleteAndroid && $.inArray(realPlatform, ["ios", "android", "win8"]) > -1;
                return isNativeScrollDevice
            };
        DX.support = {
            touch: "ontouchstart" in window,
            pointer: window.navigator.pointerEnabled,
            transform3d: supportProp("transform"),
            transition: supportProp("transition"),
            transitionEndEventName: transitionEndEventNames[styleProp("transition")],
            animation: supportProp("animation"),
            nativeScrolling: isNativeScrollingSupported(),
            winJS: "WinJS" in window,
            styleProp: styleProp,
            supportProp: supportProp,
            hasKo: !!window.ko,
            hasNg: !window.ko && !!window.angular,
            inputType: function(type) {
                if (type === "text")
                    return true;
                var input = document.createElement("input");
                try {
                    input.setAttribute("type", type);
                    input.value = "wrongValue";
                    return !input.value
                }
                catch(e) {
                    return false
                }
            }
        }
    })(jQuery, DevExpress, this);
    /*! Module core, file position.js */
    (function($, DX, undefined) {
        var horzRe = /left|right/,
            vertRe = /top|bottom/,
            collisionRe = /fit|flip|none/;
        var normalizeAlign = function(raw) {
                var result = {
                        h: "center",
                        v: "center"
                    };
                var pair = DX.utils.splitPair(raw);
                if (pair)
                    $.each(pair, function() {
                        var w = String(this).toLowerCase();
                        if (horzRe.test(w))
                            result.h = w;
                        else if (vertRe.test(w))
                            result.v = w
                    });
                return result
            };
        var normalizeOffset = function(raw) {
                var values = DX.utils.stringPairToObject(raw);
                return {
                        h: values.x,
                        v: values.y
                    }
            };
        var normalizeCollision = function(raw) {
                var pair = DX.utils.splitPair(raw),
                    h = String(pair && pair[0]).toLowerCase(),
                    v = String(pair && pair[1]).toLowerCase();
                if (!collisionRe.test(h))
                    h = "none";
                if (!collisionRe.test(v))
                    v = h;
                return {
                        h: h,
                        v: v
                    }
            };
        var getAlignFactor = function(align) {
                switch (align) {
                    case"center":
                        return 0.5;
                    case"right":
                    case"bottom":
                        return 1;
                    default:
                        return 0
                }
            };
        var inverseAlign = function(align) {
                switch (align) {
                    case"left":
                        return "right";
                    case"right":
                        return "left";
                    case"top":
                        return "bottom";
                    case"bottom":
                        return "top";
                    default:
                        return align
                }
            };
        var calculateOversize = function(data, bounds) {
                var oversize = 0;
                if (data.myLocation < bounds.min)
                    oversize += bounds.min - data.myLocation;
                if (data.myLocation > bounds.max)
                    oversize += data.myLocation - bounds.max;
                return oversize
            };
        var initMyLocation = function(data) {
                data.myLocation = data.atLocation + getAlignFactor(data.atAlign) * data.atSize - getAlignFactor(data.myAlign) * data.mySize + data.offset
            };
        var decolliders = {
                fit: function(data, bounds) {
                    var result = false;
                    if (data.myLocation > bounds.max) {
                        data.myLocation = bounds.max;
                        result = true
                    }
                    if (data.myLocation < bounds.min) {
                        data.myLocation = bounds.min;
                        result = true
                    }
                    return result
                },
                flip: function(data, bounds) {
                    if (data.myAlign === "center" && data.atAlign === "center")
                        return false;
                    if (data.myLocation < bounds.min || data.myLocation > bounds.max) {
                        var inverseData = $.extend({}, data, {
                                myAlign: inverseAlign(data.myAlign),
                                atAlign: inverseAlign(data.atAlign),
                                offset: -data.offset
                            });
                        initMyLocation(inverseData);
                        inverseData.oversize = calculateOversize(inverseData, bounds);
                        if (inverseData.myLocation >= bounds.min && inverseData.myLocation <= bounds.max || inverseData.myLocation > data.myLocation || inverseData.oversize < data.oversize) {
                            data.myLocation = inverseData.myLocation;
                            data.oversize = inverseData.oversize;
                            return true
                        }
                    }
                    return false
                }
            };
        var scrollbarWidth;
        var defaultPositionResult = {
                h: {
                    location: 0,
                    flip: false,
                    fit: false,
                    oversize: 0
                },
                v: {
                    location: 0,
                    flip: false,
                    fit: false,
                    oversize: 0
                }
            };
        var calculatePosition = function(what, options) {
                var $what = $(what),
                    currentOffset = $what.offset(),
                    result = $.extend(true, {}, defaultPositionResult, {
                        h: {location: currentOffset.left},
                        v: {location: currentOffset.top}
                    });
                if (!options)
                    return result;
                var my = normalizeAlign(options.my),
                    at = normalizeAlign(options.at),
                    of = options.of || window,
                    offset = normalizeOffset(options.offset),
                    collision = normalizeCollision(options.collision),
                    viewportOffset = normalizeOffset(options.viewportOffset);
                var h = {
                        mySize: $what.outerWidth(),
                        myAlign: my.h,
                        atAlign: at.h,
                        offset: offset.h,
                        collision: collision.h,
                        viewportOffset: viewportOffset.h
                    };
                var v = {
                        mySize: $what.outerHeight(),
                        myAlign: my.v,
                        atAlign: at.v,
                        offset: offset.v,
                        collision: collision.v,
                        viewportOffset: viewportOffset.v
                    };
                if (of.preventDefault) {
                    h.atLocation = of.pageX;
                    v.atLocation = of.pageY;
                    h.atSize = 0;
                    v.atSize = 0
                }
                else {
                    of = $(of);
                    if ($.isWindow(of[0])) {
                        h.atLocation = of.scrollLeft();
                        v.atLocation = of.scrollTop();
                        h.atSize = of.width();
                        v.atSize = of.height()
                    }
                    else if (of[0].nodeType === 9) {
                        h.atLocation = 0;
                        v.atLocation = 0;
                        h.atSize = of.width();
                        v.atSize = of.height()
                    }
                    else {
                        var o = of.offset();
                        h.atLocation = o.left;
                        v.atLocation = o.top;
                        h.atSize = of.outerWidth();
                        v.atSize = of.outerHeight()
                    }
                }
                initMyLocation(h);
                initMyLocation(v);
                var bounds = function() {
                        var win = $(window),
                            windowWidth = win.width(),
                            windowHeight = win.height(),
                            left = win.scrollLeft(),
                            top = win.scrollTop(),
                            hScrollbar = document.width > document.documentElement.clientWidth,
                            vScrollbar = document.height > document.documentElement.clientHeight,
                            hZoomLevel = DX.support.touch ? document.documentElement.clientWidth / (vScrollbar ? windowWidth - scrollbarWidth : windowWidth) : 1,
                            vZoomLevel = DX.support.touch ? document.documentElement.clientHeight / (hScrollbar ? windowHeight - scrollbarWidth : windowHeight) : 1;
                        if (scrollbarWidth === undefined)
                            scrollbarWidth = calculateScrollbarWidth();
                        return {
                                h: {
                                    min: left + h.viewportOffset,
                                    max: left + windowWidth / hZoomLevel - h.mySize - h.viewportOffset
                                },
                                v: {
                                    min: top + v.viewportOffset,
                                    max: top + windowHeight / vZoomLevel - v.mySize - v.viewportOffset
                                }
                            }
                    }();
                h.oversize = calculateOversize(h, bounds.h);
                v.oversize = calculateOversize(v, bounds.v);
                if (decolliders[h.collision])
                    result.h[h.collision] = decolliders[h.collision](h, bounds.h);
                if (decolliders[v.collision])
                    result.v[v.collision] = decolliders[v.collision](v, bounds.v);
                $.extend(true, result, {
                    h: {
                        location: Math.round(h.myLocation),
                        oversize: Math.round(h.oversize)
                    },
                    v: {
                        location: Math.round(v.myLocation),
                        oversize: Math.round(v.oversize)
                    }
                });
                return result
            };
        var position = function(what, options) {
                var $what = $(what);
                if (!options)
                    return $what.offset();
                DX.translator.resetPosition($what);
                var offset = $what.offset(),
                    targetPosition = options.h && options.v ? options : calculatePosition($what, options);
                DX.translator.move($what, {
                    left: Math.round(targetPosition.h.location - offset.left),
                    top: Math.round(targetPosition.v.location - offset.top)
                });
                return targetPosition
            };
        $.extend(DX, {
            calculatePosition: calculatePosition,
            position: position,
            inverseAlign: inverseAlign
        });
        var calculateScrollbarWidth = function() {
                var $scrollDiv = $("<div>").css({
                        width: 100,
                        height: 100,
                        overflow: "scroll",
                        position: "absolute",
                        top: -9999
                    }).appendTo($("body")),
                    result = $scrollDiv.get(0).offsetWidth - $scrollDiv.get(0).clientWidth;
                $scrollDiv.remove();
                return result
            }
    })(jQuery, DevExpress);
    /*! Module core, file action.js */
    (function($, DX, undefined) {
        var actionExecutors = {};
        var registerExecutor = function(name, executor) {
                if ($.isPlainObject(name)) {
                    $.each(name, registerExecutor);
                    return
                }
                actionExecutors[name] = executor
            };
        var unregisterExecutor = function(name) {
                var args = $.makeArray(arguments);
                $.each(args, function() {
                    delete actionExecutors[this]
                })
            };
        registerExecutor({
            func: {execute: function(e) {
                    if ($.isFunction(e.action)) {
                        e.result = e.action.apply(e.context, e.args);
                        e.handled = true
                    }
                }},
            url: {execute: function(e) {
                    if (typeof e.action === "string" && e.action.charAt(0) !== "#")
                        document.location = e.action
                }},
            hash: {execute: function(e) {
                    if (typeof e.action === "string" && e.action.charAt(0) === "#")
                        document.location.hash = e.action
                }}
        });
        var Action = DX.Class.inherit({
                ctor: function(action, config) {
                    config = config || {};
                    this._action = action || $.noop;
                    this._context = config.context || window;
                    this._beforeExecute = config.beforeExecute || $.noop;
                    this._afterExecute = config.afterExecute || $.noop;
                    this._component = config.component;
                    this._excludeValidators = config.excludeValidators
                },
                execute: function() {
                    var e = {
                            action: this._action,
                            args: Array.prototype.slice.call(arguments),
                            context: this._context,
                            component: this._component,
                            cancel: false,
                            handled: false
                        };
                    if (!this._validateAction(e))
                        return;
                    this._beforeExecute.call(this._context, e);
                    if (e.cancel)
                        return;
                    var result = this._executeAction(e);
                    this._afterExecute.call(this._context, e);
                    return result
                },
                _validateAction: function(e) {
                    var excludeValidators = this._excludeValidators;
                    $.each(actionExecutors, function(name, executor) {
                        if (excludeValidators && $.inArray(name, excludeValidators) > -1)
                            return;
                        if (executor.validate)
                            executor.validate(e);
                        if (e.cancel)
                            return false
                    });
                    return !e.cancel
                },
                _executeAction: function(e) {
                    var result;
                    $.each(actionExecutors, function(index, executor) {
                        if (executor.execute)
                            executor.execute(e);
                        if (e.handled) {
                            result = e.result;
                            return false
                        }
                    });
                    return result
                }
            });
        $.extend(DX, {
            registerActionExecutor: registerExecutor,
            unregisterActionExecutor: unregisterExecutor,
            Action: Action
        });
        DX.__internals = {actionExecutors: actionExecutors}
    })(jQuery, DevExpress);
    /*! Module core, file translator.js */
    (function($, DX, undefined) {
        var support = DX.support,
            TRANSLATOR_DATA_KEY = "dxTranslator",
            TRANSFORM_MATRIX_REGEX = /matrix(3d)?\((.+?)\)/,
            TRANSLATE_REGEX = /translate(?:3d)?\((.+?)\)/;
        var locate = function($element) {
                var result,
                    position,
                    finalPosition;
                if (support.transform3d) {
                    var translate = getTranslate($element);
                    result = {
                        left: translate.x,
                        top: translate.y
                    }
                }
                else {
                    var originalTop = $element.css("top"),
                        originalLeft = $element.css("left");
                    position = $element.position();
                    $element.css({
                        transform: "none",
                        top: 0,
                        left: 0
                    });
                    clearCache($element);
                    finalPosition = $element.position();
                    result = {
                        left: position.left - finalPosition.left || parseInt(originalLeft) || 0,
                        top: position.top - finalPosition.top || parseInt(originalTop) || 0
                    };
                    $element.css({
                        top: originalTop,
                        left: originalLeft
                    })
                }
                return result
            };
        var move = function($element, position) {
                if (!support.transform3d) {
                    $element.css(position);
                    return
                }
                var translate = getTranslate($element),
                    left = position.left,
                    top = position.top;
                if (left !== undefined)
                    translate.x = left || 0;
                if (top !== undefined)
                    translate.y = top || 0;
                $element.css({transform: getTranslateCss(translate)});
                if (isPersentValue(left) || isPersentValue(top))
                    clearCache($element)
            };
        var isPersentValue = function(value) {
                return $.type(value) === "string" && value[value.length - 1] === "%"
            };
        var getTranslate = function($element) {
                var result = $element.data(TRANSLATOR_DATA_KEY);
                if (!result) {
                    var transformValue = $element.css("transform") || getTranslateCss({
                            x: 0,
                            y: 0
                        }),
                        matrix = transformValue.match(TRANSFORM_MATRIX_REGEX),
                        is3D = matrix && matrix[1];
                    if (matrix) {
                        matrix = matrix[2].split(",");
                        if (is3D === "3d")
                            matrix = matrix.slice(12, 15);
                        else {
                            matrix.push(0);
                            matrix = matrix.slice(4, 7)
                        }
                    }
                    else
                        matrix = [0, 0, 0];
                    result = {
                        x: parseFloat(matrix[0]),
                        y: parseFloat(matrix[1]),
                        z: parseFloat(matrix[2])
                    };
                    cacheTranslate($element, result)
                }
                return result
            };
        var cacheTranslate = function($element, translate) {
                $element.data(TRANSLATOR_DATA_KEY, translate)
            };
        var clearCache = function($element) {
                $element.removeData(TRANSLATOR_DATA_KEY)
            };
        var resetPosition = function($element) {
                $element.css({
                    left: 0,
                    top: 0,
                    transform: "none"
                });
                clearCache($element)
            };
        var parseTranslate = function(translateString) {
                var result = translateString.match(TRANSLATE_REGEX);
                if (!result || !result[1])
                    return;
                result = result[1].split(",");
                result = {
                    x: parseFloat(result[0]),
                    y: parseFloat(result[1]),
                    z: parseFloat(result[2])
                };
                return result
            };
        var getTranslateCss = function(translate) {
                translate.x = translate.x || 0;
                translate.y = translate.y || 0;
                var xValueString = isPersentValue(translate.x) ? translate.x : translate.x + "px";
                var yValueString = isPersentValue(translate.y) ? translate.y : translate.y + "px";
                return "translate(" + xValueString + ", " + yValueString + ")"
            };
        DX.translator = {
            move: move,
            locate: locate,
            clearCache: clearCache,
            parseTranslate: parseTranslate,
            getTranslate: getTranslate,
            getTranslateCss: getTranslateCss,
            resetPosition: resetPosition
        }
    })(jQuery, DevExpress);
    /*! Module core, file animationFrame.js */
    (function($, DX, undefined) {
        var FRAME_ANIMATION_STEP_TIME = 1000 / 60,
            requestAnimationFrame = function(callback, element) {
                return this.setTimeout(callback, FRAME_ANIMATION_STEP_TIME)
            },
            cancelAnimationFrame = function(requestID) {
                return this.clearTimeout(requestID)
            },
            nativeRequestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame,
            nativeCancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame;
        if (nativeRequestAnimationFrame && nativeCancelAnimationFrame) {
            requestAnimationFrame = nativeRequestAnimationFrame;
            cancelAnimationFrame = nativeCancelAnimationFrame
        }
        if (nativeRequestAnimationFrame && !nativeCancelAnimationFrame) {
            var cancelledRequests = {};
            requestAnimationFrame = function(callback) {
                var requestId = nativeRequestAnimationFrame.call(window, function() {
                        try {
                            if (requestId in cancelledRequests)
                                return;
                            callback.apply(this, arguments)
                        }
                        finally {
                            delete cancelledRequests[requestId]
                        }
                    });
                return requestId
            };
            cancelAnimationFrame = function(requestId) {
                cancelledRequests[requestId] = true
            }
        }
        requestAnimationFrame = $.proxy(requestAnimationFrame, window);
        cancelAnimationFrame = $.proxy(cancelAnimationFrame, window);
        $.extend(DX, {
            requestAnimationFrame: requestAnimationFrame,
            cancelAnimationFrame: cancelAnimationFrame
        })
    })(jQuery, DevExpress);
    /*! Module core, file animator.js */
    (function($, DX, undefined) {
        DX.Animator = DX.Class.inherit({
            ctor: function() {
                this._finished = true;
                this._stopped = false
            },
            start: function() {
                this._stopped = false;
                this._finished = false;
                this._stepCore()
            },
            stop: function() {
                this._stopped = true
            },
            _stepCore: function() {
                if (this._isStopped()) {
                    this._stop();
                    return
                }
                if (this._isFinished()) {
                    this._finished = true;
                    this._complete();
                    return
                }
                this._step();
                DX.requestAnimationFrame.call(window, $.proxy(this._stepCore, this))
            },
            _step: DX.abstract,
            _isFinished: $.noop,
            _stop: $.noop,
            _complete: $.noop,
            _isStopped: function() {
                return this._stopped
            },
            inProgress: function() {
                return !(this._stopped || this._finished)
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file fx.js */
    (function($, DX, undefined) {
        var translator = DX.translator,
            support = DX.support,
            transitionEndEventName = support.transitionEndEventName + ".dxFX";
        var CSS_TRANSITION_EASING_REGEX = /cubic-bezier\((\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\)/,
            RELATIVE_VALUE_REGEX = /^([+-])=(.*)/i,
            ANIM_DATA_KEY = "dxAnimData",
            ANIM_QUEUE_KEY = "dxAnimQueue",
            TRANSFORM_PROP = "transform";
        var TransitionAnimationStrategy = {
                animate: function($element, config) {
                    var that = this,
                        deferred = $.Deferred();
                    config.transitionAnimation = {finish: function() {
                            that._cleanup($element, config);
                            deferred.resolveWith($element, [config, $element])
                        }};
                    this._startAnimation($element, config);
                    this._completeAnimationCallback($element, config).done(function() {
                        config.transitionAnimation.finish()
                    });
                    if (!config.duration)
                        config.transitionAnimation.finish();
                    return deferred.promise()
                },
                _completeAnimationCallback: function($element, config) {
                    var startTime = $.now() + config.delay,
                        deferred = $.Deferred(),
                        transitionEndFired = $.Deferred(),
                        simulatedTransitionEndFired = $.Deferred();
                    $element.one(transitionEndEventName, function(e) {
                        if ($.now() - startTime >= config.duration)
                            transitionEndFired.reject()
                    });
                    config.transitionAnimation.simulatedEndEventTimer = setTimeout(function() {
                        simulatedTransitionEndFired.reject()
                    }, config.duration + config.delay);
                    $.when(transitionEndFired, simulatedTransitionEndFired).fail($.proxy(function() {
                        deferred.resolve()
                    }, this));
                    return deferred.promise()
                },
                _startAnimation: function($element, config) {
                    $element.css("transform");
                    $element.css({
                        transitionProperty: "all",
                        transitionDelay: config.delay + "ms",
                        transitionDuration: config.duration + "ms",
                        transitionTimingFunction: config.easing
                    });
                    setProps($element, config.to)
                },
                _cleanup: function($element, config) {
                    $element.css("transition", "none").off(transitionEndEventName);
                    clearTimeout(config.transitionAnimation.simulatedEndEventTimer)
                },
                stop: function($element, config, jumpToEnd) {
                    if (!config)
                        return;
                    if (jumpToEnd)
                        config.transitionAnimation.finish();
                    else {
                        $.each(config.to, function(key) {
                            $element.css(key, $element.css(key))
                        });
                        this._cleanup($element, config)
                    }
                }
            };
        var FrameAnimationStrategy = {
                animate: function($element, config) {
                    var deferred = $.Deferred(),
                        that = this;
                    if (!config)
                        return deferred.reject().promise();
                    $.each(config.to, function(prop) {
                        if (config.from[prop] === undefined)
                            config.from[prop] = that._normalizeValue($element.css(prop))
                    });
                    if (config.to[TRANSFORM_PROP]) {
                        config.from[TRANSFORM_PROP] = that._parseTransform(config.from[TRANSFORM_PROP]);
                        config.to[TRANSFORM_PROP] = that._parseTransform(config.to[TRANSFORM_PROP])
                    }
                    config.frameAnimation = {
                        to: config.to,
                        from: config.from,
                        currentValue: config.from,
                        easing: convertTransitionTimingFuncToJQueryEasing(config.easing),
                        duration: config.duration,
                        startTime: (new Date).valueOf(),
                        finish: function() {
                            this.currentValue = this.to;
                            this.draw();
                            deferred.resolve()
                        },
                        draw: function() {
                            var currentValue = $.extend({}, this.currentValue);
                            if (currentValue[TRANSFORM_PROP])
                                currentValue[TRANSFORM_PROP] = $.map(currentValue[TRANSFORM_PROP], function(value, prop) {
                                    if (prop === "translate")
                                        return translator.getTranslateCss(value);
                                    else if (prop === "scale")
                                        return "scale(" + value + ")";
                                    else if (prop.substr(0, prop.length - 1) === "rotate")
                                        return prop + "(" + value + "deg)"
                                }).join(" ");
                            $element.css(currentValue)
                        }
                    };
                    if (config.delay) {
                        config.frameAnimation.startTime += config.delay;
                        config.frameAnimation.delayTimeout = setTimeout(function() {
                            that._animationStep($element, config)
                        }, config.delay)
                    }
                    else
                        that._animationStep($element, config);
                    return deferred.promise()
                },
                _parseTransform: function(transformString) {
                    var result = {};
                    $.each(transformString.match(/(\w|\d)+\([^\)]*\)\s*/g), function(i, part) {
                        var translateData = translator.parseTranslate(part),
                            scaleData = part.match(/scale\((.+?)\)/),
                            rotateData = part.match(/(rotate.)\((.+)deg\)/);
                        if (translateData)
                            result.translate = translateData;
                        if (scaleData && scaleData[1])
                            result.scale = parseFloat(scaleData[1]);
                        if (rotateData && rotateData[1])
                            result[rotateData[1]] = parseFloat(rotateData[2])
                    });
                    return result
                },
                stop: function($element, config, jumpToEnd) {
                    var frameAnimation = config && config.frameAnimation;
                    if (!frameAnimation)
                        return;
                    clearTimeout(frameAnimation.delayTimeout);
                    if (jumpToEnd)
                        frameAnimation.finish();
                    delete config.frameAnimation
                },
                _animationStep: function($element, config) {
                    var frameAnimation = config && config.frameAnimation;
                    if (!frameAnimation)
                        return;
                    var now = (new Date).valueOf();
                    if (now >= frameAnimation.startTime + frameAnimation.duration) {
                        frameAnimation.finish();
                        return
                    }
                    frameAnimation.currentValue = this._calcStepValue(frameAnimation, now - frameAnimation.startTime);
                    frameAnimation.draw();
                    DX.requestAnimationFrame($.proxy(function() {
                        this._animationStep($element, config)
                    }, this))
                },
                _calcStepValue: function(frameAnimation, currentDuration) {
                    var calcValueRecursively = function(from, to) {
                            var result = $.isArray(to) ? [] : {};
                            var calcEasedValue = function(propName) {
                                    var x = currentDuration / frameAnimation.duration,
                                        t = currentDuration,
                                        b = 1 * from[propName],
                                        c = to[propName] - from[propName],
                                        d = frameAnimation.duration;
                                    return $.easing[frameAnimation.easing](x, t, b, c, d)
                                };
                            $.each(to, function(propName, endPropValue) {
                                if (typeof endPropValue === "string" && parseFloat(endPropValue, 10) === false)
                                    return true;
                                result[propName] = typeof endPropValue === "object" ? calcValueRecursively(from[propName], endPropValue) : calcEasedValue(propName)
                            });
                            return result
                        };
                    return calcValueRecursively(frameAnimation.from, frameAnimation.to)
                },
                _normalizeValue: function(value) {
                    var numericValue = parseFloat(value, 10);
                    if (numericValue === false)
                        return value;
                    return numericValue
                }
            };
        var animationStrategies = {
                transition: support.transition ? TransitionAnimationStrategy : FrameAnimationStrategy,
                frame: FrameAnimationStrategy
            };
        var getAnimationStrategy = function(config) {
                return animationStrategies[config && config.strategy || "transition"]
            };
        var TransitionTimingFuncMap = {
                linear: "cubic-bezier(0, 0, 1, 1)",
                ease: "cubic-bezier(0.25, 0.1, 0.25, 1)",
                "ease-in": "cubic-bezier(0.42, 0, 1, 1)",
                "ease-out": "cubic-bezier(0, 0, 0.58, 1)",
                "ease-in-out": "cubic-bezier(0.42, 0, 0.58, 1)"
            };
        var convertTransitionTimingFuncToJQueryEasing = function(cssTransitionEasing) {
                cssTransitionEasing = TransitionTimingFuncMap[cssTransitionEasing] || cssTransitionEasing;
                var bezCoeffs = cssTransitionEasing.match(CSS_TRANSITION_EASING_REGEX);
                if (!bezCoeffs)
                    return "linear";
                bezCoeffs = bezCoeffs.slice(1, 5);
                $.each(bezCoeffs, function(index, value) {
                    bezCoeffs[index] = parseFloat(value)
                });
                var easingName = "cubicbezier_" + bezCoeffs.join("_").replace(/\./g, "p");
                if (!$.isFunction($.easing[easingName])) {
                    var polynomBezier = function(x1, y1, x2, y2) {
                            var Cx = 3 * x1,
                                Bx = 3 * (x2 - x1) - Cx,
                                Ax = 1 - Cx - Bx,
                                Cy = 3 * y1,
                                By = 3 * (y2 - y1) - Cy,
                                Ay = 1 - Cy - By;
                            var bezierX = function(t) {
                                    return t * (Cx + t * (Bx + t * Ax))
                                };
                            var bezierY = function(t) {
                                    return t * (Cy + t * (By + t * Ay))
                                };
                            var findXfor = function(t) {
                                    var x = t,
                                        i = 0,
                                        z;
                                    while (i < 14) {
                                        z = bezierX(x) - t;
                                        if (Math.abs(z) < 1e-3)
                                            break;
                                        x = x - z / derivativeX(x);
                                        i++
                                    }
                                    return x
                                };
                            var derivativeX = function(t) {
                                    return Cx + t * (2 * Bx + t * 3 * Ax)
                                };
                            return function(t) {
                                    return bezierY(findXfor(t))
                                }
                        };
                    $.easing[easingName] = function(x, t, b, c, d) {
                        return c * polynomBezier(bezCoeffs[0], bezCoeffs[1], bezCoeffs[2], bezCoeffs[3])(t / d) + b
                    }
                }
                return easingName
            };
        var baseConfigValidator = function(config, animationType) {
                $.each(["from", "to"], function() {
                    if (!$.isPlainObject(config[this]))
                        throw Error("Animation with the '" + animationType + "' type requires '" + this + "' configuration as an plain object.");
                })
            };
        var CustomAnimationConfigurator = {setup: function($element, config){}};
        var SlideAnimationConfigurator = {
                validateConfig: function(config) {
                    baseConfigValidator(config, "slide")
                },
                setup: function($element, config) {
                    var location = translator.locate($element);
                    this._setUpConfig(location, config.from);
                    this._setUpConfig(location, config.to);
                    translator.clearCache($element);
                    if (!support.transform3d && $element.css("position") === "static")
                        $element.css("position", "relative")
                },
                _setUpConfig: function(location, config) {
                    config.left = "left" in config ? config.left : "+=0";
                    config.top = "top" in config ? config.top : "+=0";
                    this._initNewPosition(location, config)
                },
                _initNewPosition: function(location, config) {
                    var position = {
                            left: config.left,
                            top: config.top
                        };
                    delete config.left;
                    delete config.top;
                    var relativeValue = this._getRelativeValue(position.left);
                    if (relativeValue !== undefined)
                        position.left = relativeValue + location.left;
                    else
                        config.left = 0;
                    relativeValue = this._getRelativeValue(position.top);
                    if (relativeValue !== undefined)
                        position.top = relativeValue + location.top;
                    else
                        config.top = 0;
                    var translate = {
                            x: 0,
                            y: 0
                        };
                    if (support.transform3d)
                        translate = {
                            x: position.left,
                            y: position.top
                        };
                    else {
                        config.left = position.left;
                        config.top = position.top
                    }
                    config[TRANSFORM_PROP] = translator.getTranslateCss(translate)
                },
                _getRelativeValue: function(value) {
                    var relativeValue;
                    if (typeof value === "string" && (relativeValue = RELATIVE_VALUE_REGEX.exec(value)))
                        return parseInt(relativeValue[1] + "1") * relativeValue[2]
                }
            };
        var FadeAnimationConfigurator = {setup: function($element, config) {
                    var from = config.from,
                        fromOpacity = $.isPlainObject(from) ? $element.css("opacity") : String(from),
                        toOpacity = String(config.to);
                    config.from = {opacity: fromOpacity};
                    config.to = {opacity: toOpacity}
                }};
        var PopAnimationConfigurator = {
                validateConfig: function(config) {
                    baseConfigValidator(config, "pop")
                },
                setup: function($element, config) {
                    var from = config.from,
                        to = config.to,
                        fromOpacity = "opacity" in from ? from.opacity : $element.css("opacity"),
                        toOpacity = "opacity" in to ? to.opacity : 1,
                        fromScale = "scale" in from ? from.scale : 0,
                        toScale = "scale" in to ? to.scale : 1;
                    config.from = {opacity: fromOpacity};
                    var translate = translator.getTranslate($element);
                    config.from[TRANSFORM_PROP] = this._getCssTransform(translate, fromScale);
                    config.to = {opacity: toOpacity};
                    config.to[TRANSFORM_PROP] = this._getCssTransform(translate, toScale)
                },
                _getCssTransform: function(translate, scale) {
                    return translator.getTranslateCss(translate) + "scale(" + scale + ")"
                }
            };
        var animationConfigurators = {
                custom: CustomAnimationConfigurator,
                slide: SlideAnimationConfigurator,
                fade: FadeAnimationConfigurator,
                pop: PopAnimationConfigurator
            };
        var getAnimationConfigurator = function(type) {
                var result = animationConfigurators[type];
                if (!result)
                    throw Error("Unknown animation type \"" + type + "\"");
                return result
            };
        var defaultConfig = {
                type: "custom",
                from: {},
                to: {},
                duration: 400,
                start: $.noop,
                complete: $.noop,
                easing: "ease",
                delay: 0
            };
        var animate = function(element, config) {
                var $element = $(element);
                config = $.extend(true, {}, defaultConfig, config);
                if (!$element.length)
                    return $.Deferred().resolve().promise();
                var configurator = getAnimationConfigurator(config.type);
                if ($.isFunction(configurator.validateConfig))
                    configurator.validateConfig(config);
                return pushInAnimationQueue($element, config)
            };
        var pushInAnimationQueue = function($element, config) {
                config.deferred = config.deferred || $.Deferred();
                var queueData = getAnimQueueData($element);
                writeAnimQueueData($element, queueData);
                queueData.push(config);
                if (!isAnimating($element))
                    shiftFromAnimationQueue($element, queueData);
                return config.deferred.promise()
            };
        var getAnimQueueData = function($element) {
                return $element.data(ANIM_QUEUE_KEY) || []
            };
        var writeAnimQueueData = function($element, queueData) {
                $element.data(ANIM_QUEUE_KEY, queueData)
            };
        var destroyAnimQueueData = function($element) {
                $element.removeData(ANIM_QUEUE_KEY)
            };
        var isAnimating = function($element) {
                return !!$element.data(ANIM_DATA_KEY)
            };
        var shiftFromAnimationQueue = function($element, queueData) {
                var queueData = getAnimQueueData($element);
                if (!queueData.length)
                    return;
                var config = queueData.shift();
                if (queueData.length === 0)
                    destroyAnimQueueData($element);
                executeAnimation($element, config).done(function() {
                    shiftFromAnimationQueue($element)
                })
            };
        var executeAnimation = function($element, config) {
                setupPosition($element, config.from);
                setupPosition($element, config.to);
                var configurator = getAnimationConfigurator(config.type);
                configurator.setup($element, config);
                $element.data(ANIM_DATA_KEY, config);
                if (DX.fx.off)
                    config.duration = 0;
                setProps($element, config.from);
                config.start.apply(this, [$element, config]);
                return getAnimationStrategy(config).animate($element, config).done(function() {
                        $element.removeData(ANIM_DATA_KEY);
                        config.complete.apply(this, [$element, config]);
                        config.deferred.resolveWith(this, [$element, config])
                    })
            };
        var setupPosition = function($element, config) {
                if (!config.position)
                    return;
                var position = DX.calculatePosition($element, config.position),
                    offset = $element.offset(),
                    currentPosition = $element.position();
                $.extend(config, {
                    left: position.h.location - offset.left + currentPosition.left,
                    top: position.v.location - offset.top + currentPosition.top
                });
                delete config.position
            };
        var setProps = function($element, props) {
                $.each(props, function(key, value) {
                    $element.css(key, value)
                })
            };
        var stop = function(element, jumpToEnd) {
                var $element = $(element),
                    queueData = getAnimQueueData($element);
                $.each(queueData, function(_, config) {
                    config.duration = 0
                });
                var config = $element.data(ANIM_DATA_KEY);
                getAnimationStrategy(config).stop($element, config, jumpToEnd);
                $element.removeData(ANIM_DATA_KEY);
                destroyAnimQueueData($element)
            };
        DX.fx = {
            off: false,
            animationTypes: animationConfigurators,
            animate: animate,
            isAnimating: isAnimating,
            stop: stop
        };
        DX.fx.__internals = {convertTransitionTimingFuncToJQueryEasing: convertTransitionTimingFuncToJQueryEasing}
    })(jQuery, DevExpress);
    /*! Module core, file endpointSelector.js */
    (function($, DX, undefined) {
        var location = window.location,
            DXPROXY_HOST = "dxproxy.devexpress.com:8000",
            WIN_JS = location.protocol === "ms-appx:",
            IS_DXPROXY = location.host === DXPROXY_HOST,
            IS_LOCAL = isLocalHostName(location.hostname);
        function isLocalHostName(url) {
            return /^(localhost$|127\.)/i.test(url)
        }
        var extractProxyAppId = function() {
                return location.pathname.split("/")[1]
            };
        var formatProxyUrl = function(localUrl) {
                var urlData = DX.parseUrl(localUrl);
                if (!isLocalHostName(urlData.hostname))
                    return localUrl;
                return "http://" + DXPROXY_HOST + "/" + extractProxyAppId() + "_" + urlData.port + urlData.pathname + urlData.search
            };
        var EndpointSelector = DX.EndpointSelector = function(config) {
                this.config = config
            };
        EndpointSelector.prototype = {urlFor: function(key) {
                var bag = this.config[key];
                if (!bag)
                    throw Error("Unknown endpoint key");
                if (IS_DXPROXY)
                    return formatProxyUrl(bag.local);
                if (bag.production)
                    if (WIN_JS && !Debug.debuggerEnabled || !WIN_JS && !IS_LOCAL)
                        return bag.production;
                return bag.local
            }}
    })(jQuery, DevExpress);
    /*! Module core, file formatHelper.js */
    (function($, DX, undefined) {
        var utils = DX.utils;
        DX.NumericFormat = {
            currency: 'C',
            fixedpoint: 'N',
            exponential: '',
            percent: 'P',
            decimal: 'D'
        };
        DX.LargeNumberFormatPostfixes = {
            1: 'K',
            2: 'M',
            3: 'B',
            4: 'T'
        };
        var MAX_LARGE_NUMBER_POWER = 4,
            DECIMAL_BASE = 10;
        DX.LargeNumberFormatPowers = {
            largenumber: 'auto',
            thousands: 1,
            millions: 2,
            billions: 3,
            trillions: 4
        };
        DX.DateTimeFormat = {
            longdate: 'D',
            longtime: 'T',
            monthandday: 'M',
            monthandyear: 'Y',
            quarterandyear: 'qq',
            shortdate: 'd',
            shorttime: 't',
            millisecond: 'fff',
            second: 'T',
            minute: 't',
            hour: 't',
            day: 'dd',
            week: 'dd',
            month: 'MMMM',
            quarter: 'qq',
            year: 'yyyy',
            longdatelongtime: 'D',
            shortdateshorttime: 'd'
        };
        DX.formatHelper = {
            romanDigits: ['I', 'II', 'III', 'IV'],
            _addFormatSeparator: function(format1, format2) {
                var separator = ' ';
                if (format2)
                    return format1 + separator + format2;
                return format1
            },
            _getDateTimeFormatPattern: function(dateTimeFormat) {
                return Globalize.findClosestCulture().calendar.patterns[DX.DateTimeFormat[dateTimeFormat.toLowerCase()]]
            },
            _isDateFormatContains: function(format) {
                var result = false;
                $.each(DX.DateTimeFormat, function(key, value) {
                    result = key === format.toLowerCase();
                    return !result
                });
                return result
            },
            getQuarter: function(month) {
                return Math.floor(month / 3)
            },
            getQuarterString: function(date, format) {
                var resultQuarter = '',
                    quarter = this.getQuarter(date.getMonth());
                switch (format) {
                    case'q':
                        resultQuarter = this.romanDigits[quarter];
                        break;
                    case'qq':
                        resultQuarter = 'Q' + this.romanDigits[quarter];
                        break;
                    case'Q':
                        resultQuarter = (quarter + 1).toString();
                        break;
                    case'QQ':
                        resultQuarter = 'Q' + (quarter + 1).toString();
                        break
                }
                return resultQuarter
            },
            getFirstQuarterMonth: function(month) {
                return this.getQuarter(month) * 3
            },
            _formatCustomString: function(value, format) {
                var regExp = /qq|q|QQ|Q/g,
                    quarterFormat,
                    result = '',
                    index = 0;
                regExp.lastIndex = 0;
                while (index < format.length) {
                    quarterFormat = regExp.exec(format);
                    if (!quarterFormat || quarterFormat.index > index)
                        result += Globalize.format(value, format.substring(index, quarterFormat ? quarterFormat.index : format.length));
                    if (quarterFormat) {
                        result += this.getQuarterString(value, quarterFormat[0]);
                        index = quarterFormat.index + quarterFormat[0].length
                    }
                    else
                        index = format.length
                }
                return result
            },
            _parseNumberFormatString: function(format) {
                var formatList,
                    formatObject = {};
                if (!format || typeof format !== 'string')
                    return;
                formatList = format.toLowerCase().split(' ');
                $.each(formatList, function(index, value) {
                    if (value in DX.NumericFormat)
                        formatObject.formatType = value;
                    else if (value in DX.LargeNumberFormatPowers)
                        formatObject.power = DX.LargeNumberFormatPowers[value]
                });
                if (formatObject.power && !formatObject.formatType)
                    formatObject.formatType = 'fixedpoint';
                if (formatObject.formatType)
                    return formatObject
            },
            _calculateNumberPower: function(value, base, minPower, maxPower) {
                var number = Math.abs(value);
                var power = 0;
                if (number > 1)
                    while (number && number >= base && (maxPower === undefined || power < maxPower)) {
                        power++;
                        number = number / base
                    }
                else if (number > 0 && number < 1)
                    while (number < 1 && (minPower === undefined || power > minPower)) {
                        power--;
                        number = number * base
                    }
                return power
            },
            _getNumberByPower: function(number, power, base) {
                var result = number;
                while (power > 0) {
                    result = result / base;
                    power--
                }
                while (power < 0) {
                    result = result * base;
                    power++
                }
                return result
            },
            _formatNumber: function(value, formatObject, precision) {
                var powerPostfix;
                if (formatObject.power === 'auto')
                    formatObject.power = this._calculateNumberPower(value, 1000, 0, MAX_LARGE_NUMBER_POWER);
                if (formatObject.power)
                    value = this._getNumberByPower(value, formatObject.power, 1000);
                powerPostfix = DX.LargeNumberFormatPostfixes[formatObject.power] || '';
                return this._formatNumberCore(value, formatObject.formatType, precision) + powerPostfix
            },
            _formatNumberExponential: function(value, precision) {
                var power = this._calculateNumberPower(value, DECIMAL_BASE),
                    number = this._getNumberByPower(value, power, DECIMAL_BASE),
                    powString;
                precision = precision === undefined ? 1 : precision;
                if (number.toFixed(precision || 0) >= DECIMAL_BASE) {
                    power++;
                    number = number / DECIMAL_BASE
                }
                powString = (power >= 0 ? '+' : '') + power.toString();
                return this._formatNumberCore(number, 'fixedpoint', precision) + 'E' + powString
            },
            _formatNumberCore: function(value, format, precision) {
                if (format === 'exponential')
                    return this._formatNumberExponential(value, precision);
                else
                    return Globalize.format(value, DX.NumericFormat[format] + (utils.isNumber(precision) ? precision : 0))
            },
            _formatDate: function(date, format, formatString) {
                var resultFormat = DX.DateTimeFormat[format.toLowerCase()];
                format = format.toLowerCase();
                if (format === 'quarterandyear')
                    resultFormat = this.getQuarterString(date, resultFormat) + ' yyyy';
                if (format === 'quarter')
                    return this.getQuarterString(date, resultFormat);
                if (format === 'longdatelongtime')
                    return this._formatDate(date, 'longdate') + ' ' + this._formatDate(date, 'longtime');
                if (format === 'shortdateshorttime')
                    return this._formatDate(date, 'shortDate') + ' ' + this._formatDate(date, 'shortTime');
                return Globalize.format(date, resultFormat)
            },
            format: function(value, format, precision) {
                if (format && format.format)
                    if (format.dateType)
                        return this._formatDateEx(value, format);
                    else if (utils.isNumber(value) && isFinite(value))
                        return this._formatNumberEx(value, format);
                return this._format(value, format, precision)
            },
            _format: function(value, format, precision) {
                var numberFormatObject;
                if (!utils.isString(format) || format === '' || !utils.isNumber(value) && !utils.isDate(value))
                    return utils.isDefined(value) ? value.toString() : '';
                numberFormatObject = this._parseNumberFormatString(format);
                if (utils.isNumber(value) && numberFormatObject)
                    return this._formatNumber(value, numberFormatObject, precision);
                if (utils.isDate(value) && this._isDateFormatContains(format))
                    return this._formatDate(value, format);
                if (!numberFormatObject && !this._isDateFormatContains(format))
                    return this._formatCustomString(value, format)
            },
            _formatNumberEx: function(value, formatInfo) {
                var that = this,
                    numericFormatType = DX.NumericFormat[formatInfo.format.toLowerCase()],
                    numberFormat = Globalize.culture().numberFormat,
                    currencyFormat = formatInfo.currencyCulture && Globalize.cultures[formatInfo.currencyCulture] ? Globalize.cultures[formatInfo.currencyCulture].numberFormat.currency : numberFormat.currency,
                    percentFormat = numberFormat.percent,
                    formatSettings = that._getUnitFormatSettings(value, formatInfo),
                    unit = formatSettings.unit,
                    precision = formatSettings.precision,
                    showTrailingZeros = formatSettings.showTrailingZeros,
                    includeGroupSeparator = formatSettings.includeGroupSeparator,
                    groupSymbol = numberFormat[","],
                    floatingSymbol = numberFormat["."],
                    number,
                    isNegative,
                    pattern,
                    currentFormat,
                    regexParts = /n|\$|-|%/g,
                    result = "";
                value = that._applyUnitToValue(value, unit);
                number = Math.abs(value);
                isNegative = value < 0;
                switch (numericFormatType) {
                    case"D":
                        pattern = "n";
                        number = Math[isNegative ? "ceil" : "floor"](number);
                        if (precision > 0) {
                            var str = "" + number;
                            for (var i = str.length; i < precision; i += 1)
                                str = "0" + str;
                            number = str
                        }
                        if (isNegative)
                            number = "-" + number;
                        break;
                    case"N":
                        currentFormat = numberFormat;
                    case"C":
                        currentFormat = currentFormat || currencyFormat;
                    case"P":
                        currentFormat = currentFormat || percentFormat;
                        pattern = isNegative ? currentFormat.pattern[0] : currentFormat.pattern[1] || "n";
                        number = Globalize.format(number * (numericFormatType === "P" ? 100 : 1), "N" + precision);
                        if (!showTrailingZeros)
                            number = that._excludeTrailingZeros(number, floatingSymbol);
                        if (!includeGroupSeparator)
                            number = number.replace(new RegExp('\\' + groupSymbol, 'g'), '');
                        break;
                    default:
                        throw"Illegal numeric format: '" + numericFormatType + "'";
                }
                for (; ; ) {
                    var lastIndex = regexParts.lastIndex,
                        matches = regexParts.exec(pattern);
                    result += pattern.slice(lastIndex, matches ? matches.index : pattern.length);
                    if (matches)
                        switch (matches[0]) {
                            case"-":
                                if (/[1-9]/.test(number))
                                    result += numberFormat["-"];
                                break;
                            case"$":
                                result += currencyFormat.symbol;
                                break;
                            case"%":
                                result += percentFormat.symbol;
                                break;
                            case"n":
                                result += number + unit;
                                break
                        }
                    else
                        break
                }
                return (formatInfo.plus && value > 0 ? "+" : '') + result
            },
            _excludeTrailingZeros: function(strValue, floatingSymbol) {
                var floatingIndex = strValue.indexOf(floatingSymbol),
                    stopIndex,
                    i;
                if (floatingIndex < 0)
                    return strValue;
                stopIndex = strValue.length;
                for (i = stopIndex - 1; i >= floatingIndex && (strValue[i] === '0' || i === floatingIndex); i--)
                    stopIndex--;
                return strValue.substring(0, stopIndex)
            },
            _getUnitFormatSettings: function(value, formatInfo) {
                var unit = formatInfo.unit || '',
                    precision = formatInfo.precision || 0,
                    includeGroupSeparator = formatInfo.includeGroupSeparator || false,
                    showTrailingZeros = formatInfo.showTrailingZeros === undefined ? true : formatInfo.showTrailingZeros,
                    significantDigits = formatInfo.significantDigits || 1,
                    absValue;
                if (unit.toLowerCase() === 'auto') {
                    showTrailingZeros = false;
                    absValue = Math.abs(value);
                    if (significantDigits < 1)
                        significantDigits = 1;
                    if (absValue >= 1000000000) {
                        unit = 'B';
                        absValue /= 1000000000
                    }
                    else if (absValue >= 1000000) {
                        unit = 'M';
                        absValue /= 1000000
                    }
                    else if (absValue >= 1000) {
                        unit = 'K';
                        absValue /= 1000
                    }
                    else
                        unit = '';
                    if (absValue == 0)
                        precision = 0;
                    else if (absValue < 1) {
                        precision = significantDigits;
                        var smallValue = Math.pow(10, -significantDigits);
                        while (absValue < smallValue) {
                            smallValue /= 10;
                            precision++
                        }
                    }
                    else if (absValue >= 100)
                        precision = significantDigits - 3;
                    else if (absValue >= 10)
                        precision = significantDigits - 2;
                    else
                        precision = significantDigits - 1
                }
                if (precision < 0)
                    precision = 0;
                return {
                        unit: unit,
                        precision: precision,
                        showTrailingZeros: showTrailingZeros,
                        includeGroupSeparator: includeGroupSeparator
                    }
            },
            _applyUnitToValue: function(value, unit) {
                if (unit == 'B')
                    return value.toFixed(1) / 1000000000;
                if (unit == 'M')
                    return value / 1000000;
                if (unit == 'K')
                    return value / 1000;
                return value
            },
            _formatDateEx: function(value, formatInfo) {
                var that = this,
                    quarterPrefix = 'Q',
                    format = formatInfo.format,
                    dateType = formatInfo.dateType,
                    calendar = Globalize.culture().calendars.standard,
                    time = undefined,
                    index,
                    dateStr;
                format = format.toLowerCase();
                if (dateType !== 'num' || format === 'dayofweek')
                    switch (format) {
                        case'monthyear':
                            return that._formatDate(value, 'monthandyear');
                        case'quarteryear':
                            return that.getQuarterString(value, 'QQ') + ' ' + value.getFullYear();
                        case'daymonthyear':
                            return that._formatDate(value, dateType + 'Date');
                        case'datehour':
                            time = new Date(value.getTime());
                            time.setMinutes(0);
                            dateStr = dateType === 'timeOnly' ? '' : that._formatDate(value, dateType + 'Date');
                            return dateType === 'timeOnly' ? that._formatDate(time, 'shorttime') : dateStr + ' ' + that._formatDate(time, 'shorttime');
                        case'datehourminute':
                            dateStr = dateType === 'timeOnly' ? '' : that._formatDate(value, dateType + 'Date');
                            return dateType === 'timeOnly' ? that._formatDate(value, 'shorttime') : dateStr + ' ' + that._formatDate(value, 'shorttime');
                        case'datehourminutesecond':
                            dateStr = dateType === 'timeOnly' ? '' : that._formatDate(value, dateType + 'Date');
                            return dateType === 'timeOnly' ? that._formatDate(value, 'longtime') : dateStr + ' ' + that._formatDate(value, 'longtime');
                        case'year':
                            dateStr = value.toString();
                            return dateType === 'abbr' ? dateStr.slice(2, 4) : dateStr;
                        case'quarter':
                            return quarterPrefix + value.toString();
                        case'month':
                            index = value - 1;
                            return dateType === 'abbr' ? calendar.months.namesAbbr[index] : calendar.months.names[index];
                        case'hour':
                            if (dateType === 'long') {
                                time = new Date;
                                time.setHours(value);
                                time.setMinutes(0);
                                return that._formatDate(time, 'shorttime')
                            }
                            else
                                return value.toString();
                        case'dayofweek':
                            index = $.inArray(value, ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']);
                            if (dateType !== 'num')
                                return dateType === 'abbr' ? calendar.days.namesAbbr[index] : calendar.days.names[index];
                            else
                                return ((index - calendar.firstDay + 1 + 7) % 8).toString();
                        default:
                            return value.toString()
                    }
                else
                    return value.toString()
            },
            getTimeFormat: function(showSecond) {
                if (showSecond)
                    return this._getDateTimeFormatPattern('longtime');
                return this._getDateTimeFormatPattern('shorttime')
            },
            getDateFormatByDifferences: function(dateDifferences) {
                var resultFormat = '';
                if (dateDifferences.millisecond)
                    resultFormat = DX.DateTimeFormat.millisecond;
                if (dateDifferences.hour || dateDifferences.minute || dateDifferences.second)
                    resultFormat = this._addFormatSeparator(this.getTimeFormat(dateDifferences.second), resultFormat);
                if (dateDifferences.year && dateDifferences.month && dateDifferences.day)
                    return this._addFormatSeparator(this._getDateTimeFormatPattern('shortdate'), resultFormat);
                if (dateDifferences.year && dateDifferences.month)
                    return DX.DateTimeFormat['monthandyear'];
                if (dateDifferences.year)
                    return DX.DateTimeFormat['year'];
                if (dateDifferences.month && dateDifferences.day)
                    return this._addFormatSeparator(this._getDateTimeFormatPattern('monthandday'), resultFormat);
                if (dateDifferences.month)
                    return DX.DateTimeFormat['month'];
                if (dateDifferences.day)
                    return this._addFormatSeparator('dddd, dd', resultFormat);
                return resultFormat
            },
            getDateFormatByTicks: function(ticks) {
                var resultFormat,
                    maxDif,
                    currentDif,
                    i,
                    dateUnitInterval;
                if (ticks.length > 1) {
                    maxDif = utils.getDatesDifferences(ticks[0], ticks[1]);
                    for (i = 1; i < ticks.length - 1; i++) {
                        currentDif = utils.getDatesDifferences(ticks[i], ticks[i + 1]);
                        if (maxDif.count < currentDif.count)
                            maxDif = currentDif
                    }
                }
                else
                    maxDif = {
                        year: true,
                        month: true,
                        day: true,
                        hour: ticks[0].getHours() > 0,
                        minute: ticks[0].getMinutes() > 0,
                        second: ticks[0].getSeconds() > 0
                    };
                resultFormat = this.getDateFormatByDifferences(maxDif);
                return resultFormat
            },
            getDateFormatByTickInterval: function(startValue, endValue, tickInterval) {
                var resultFormat,
                    dateDifferences,
                    dateUnitInterval,
                    dateDifferencesConverter = {
                        quarter: 'month',
                        week: 'day'
                    },
                    correctDateDifferences = function(dateDifferences, tickInterval, value) {
                        switch (tickInterval) {
                            case'year':
                                dateDifferences.month = value;
                            case'quarter':
                            case'month':
                                dateDifferences.day = value;
                            case'week':
                            case'day':
                                dateDifferences.hour = value;
                            case'hour':
                                dateDifferences.minute = value;
                            case'minute':
                                dateDifferences.second = value;
                            case'second':
                                dateDifferences.millisecond = value
                        }
                    },
                    correctDifferencesByMaxDate = function(differences, minDate, maxDate) {
                        if (!maxDate.getMilliseconds() && maxDate.getSeconds()) {
                            if (maxDate.getSeconds() - minDate.getSeconds() === 1) {
                                differences.millisecond = true;
                                differences.second = false
                            }
                        }
                        else if (!maxDate.getSeconds() && maxDate.getMinutes()) {
                            if (maxDate.getMinutes() - minDate.getMinutes() === 1) {
                                differences.second = true;
                                differences.minute = false
                            }
                        }
                        else if (!maxDate.getMinutes() && maxDate.getHours()) {
                            if (maxDate.getHours() - minDate.getHours() === 1) {
                                differences.minute = true;
                                differences.hour = false
                            }
                        }
                        else if (!maxDate.getHours() && maxDate.getDate() > 1) {
                            if (maxDate.getDate() - minDate.getDate() === 1) {
                                differences.hour = true;
                                differences.day = false
                            }
                        }
                        else if (maxDate.getDate() === 1 && maxDate.getMonth()) {
                            if (maxDate.getMonth() - minDate.getMonth() === 1) {
                                differences.day = true;
                                differences.month = false
                            }
                        }
                        else if (!maxDate.getMonth() && maxDate.getFullYear())
                            if (maxDate.getFullYear() - minDate.getFullYear() === 1) {
                                differences.month = true;
                                differences.year = false
                            }
                    };
                tickInterval = utils.isString(tickInterval) ? tickInterval.toLowerCase() : tickInterval;
                dateDifferences = utils.getDatesDifferences(startValue, endValue);
                if (startValue !== endValue)
                    correctDifferencesByMaxDate(dateDifferences, startValue > endValue ? endValue : startValue, startValue > endValue ? startValue : endValue);
                dateUnitInterval = utils.getDateUnitInterval(dateDifferences);
                correctDateDifferences(dateDifferences, dateUnitInterval, true);
                dateUnitInterval = utils.getDateUnitInterval(tickInterval || 'second');
                correctDateDifferences(dateDifferences, dateUnitInterval, false);
                dateDifferences[dateDifferencesConverter[dateUnitInterval] || dateUnitInterval] = true;
                resultFormat = this.getDateFormatByDifferences(dateDifferences);
                return resultFormat
            }
        }
    })(jQuery, DevExpress);
    /*! Module core, file color.js */
    (function(DX, undefined) {
        var standardColorNames = {
                aliceblue: 'f0f8ff',
                antiquewhite: 'faebd7',
                aqua: '00ffff',
                aquamarine: '7fffd4',
                azure: 'f0ffff',
                beige: 'f5f5dc',
                bisque: 'ffe4c4',
                black: '000000',
                blanchedalmond: 'ffebcd',
                blue: '0000ff',
                blueviolet: '8a2be2',
                brown: 'a52a2a',
                burlywood: 'deb887',
                cadetblue: '5f9ea0',
                chartreuse: '7fff00',
                chocolate: 'd2691e',
                coral: 'ff7f50',
                cornflowerblue: '6495ed',
                cornsilk: 'fff8dc',
                crimson: 'dc143c',
                cyan: '00ffff',
                darkblue: '00008b',
                darkcyan: '008b8b',
                darkgoldenrod: 'b8860b',
                darkgray: 'a9a9a9',
                darkgreen: '006400',
                darkkhaki: 'bdb76b',
                darkmagenta: '8b008b',
                darkolivegreen: '556b2f',
                darkorange: 'ff8c00',
                darkorchid: '9932cc',
                darkred: '8b0000',
                darksalmon: 'e9967a',
                darkseagreen: '8fbc8f',
                darkslateblue: '483d8b',
                darkslategray: '2f4f4f',
                darkturquoise: '00ced1',
                darkviolet: '9400d3',
                deeppink: 'ff1493',
                deepskyblue: '00bfff',
                dimgray: '696969',
                dodgerblue: '1e90ff',
                feldspar: 'd19275',
                firebrick: 'b22222',
                floralwhite: 'fffaf0',
                forestgreen: '228b22',
                fuchsia: 'ff00ff',
                gainsboro: 'dcdcdc',
                ghostwhite: 'f8f8ff',
                gold: 'ffd700',
                goldenrod: 'daa520',
                gray: '808080',
                green: '008000',
                greenyellow: 'adff2f',
                honeydew: 'f0fff0',
                hotpink: 'ff69b4',
                indianred: 'cd5c5c',
                indigo: '4b0082',
                ivory: 'fffff0',
                khaki: 'f0e68c',
                lavender: 'e6e6fa',
                lavenderblush: 'fff0f5',
                lawngreen: '7cfc00',
                lemonchiffon: 'fffacd',
                lightblue: 'add8e6',
                lightcoral: 'f08080',
                lightcyan: 'e0ffff',
                lightgoldenrodyellow: 'fafad2',
                lightgrey: 'd3d3d3',
                lightgreen: '90ee90',
                lightpink: 'ffb6c1',
                lightsalmon: 'ffa07a',
                lightseagreen: '20b2aa',
                lightskyblue: '87cefa',
                lightslateblue: '8470ff',
                lightslategray: '778899',
                lightsteelblue: 'b0c4de',
                lightyellow: 'ffffe0',
                lime: '00ff00',
                limegreen: '32cd32',
                linen: 'faf0e6',
                magenta: 'ff00ff',
                maroon: '800000',
                mediumaquamarine: '66cdaa',
                mediumblue: '0000cd',
                mediumorchid: 'ba55d3',
                mediumpurple: '9370d8',
                mediumseagreen: '3cb371',
                mediumslateblue: '7b68ee',
                mediumspringgreen: '00fa9a',
                mediumturquoise: '48d1cc',
                mediumvioletred: 'c71585',
                midnightblue: '191970',
                mintcream: 'f5fffa',
                mistyrose: 'ffe4e1',
                moccasin: 'ffe4b5',
                navajowhite: 'ffdead',
                navy: '000080',
                oldlace: 'fdf5e6',
                olive: '808000',
                olivedrab: '6b8e23',
                orange: 'ffa500',
                orangered: 'ff4500',
                orchid: 'da70d6',
                palegoldenrod: 'eee8aa',
                palegreen: '98fb98',
                paleturquoise: 'afeeee',
                palevioletred: 'd87093',
                papayawhip: 'ffefd5',
                peachpuff: 'ffdab9',
                peru: 'cd853f',
                pink: 'ffc0cb',
                plum: 'dda0dd',
                powderblue: 'b0e0e6',
                purple: '800080',
                red: 'ff0000',
                rosybrown: 'bc8f8f',
                royalblue: '4169e1',
                saddlebrown: '8b4513',
                salmon: 'fa8072',
                sandybrown: 'f4a460',
                seagreen: '2e8b57',
                seashell: 'fff5ee',
                sienna: 'a0522d',
                silver: 'c0c0c0',
                skyblue: '87ceeb',
                slateblue: '6a5acd',
                slategray: '708090',
                snow: 'fffafa',
                springgreen: '00ff7f',
                steelblue: '4682b4',
                tan: 'd2b48c',
                teal: '008080',
                thistle: 'd8bfd8',
                tomato: 'ff6347',
                turquoise: '40e0d0',
                violet: 'ee82ee',
                violetred: 'd02090',
                wheat: 'f5deb3',
                white: 'ffffff',
                whitesmoke: 'f5f5f5',
                yellow: 'ffff00',
                yellowgreen: '9acd32'
            };
        var standardColorTypes = [{
                    re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
                    process: function(colorString) {
                        return [parseInt(colorString[1], 10), parseInt(colorString[2], 10), parseInt(colorString[3], 10)]
                    }
                }, {
                    re: /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d*\.*\d+)\)$/,
                    process: function(colorString) {
                        return [parseInt(colorString[1], 10), parseInt(colorString[2], 10), parseInt(colorString[3], 10), parseFloat(colorString[4])]
                    }
                }, {
                    re: /^#(\w{2})(\w{2})(\w{2})$/,
                    process: function(colorString) {
                        return [parseInt(colorString[1], 16), parseInt(colorString[2], 16), parseInt(colorString[3], 16)]
                    }
                }, {
                    re: /^#(\w{1})(\w{1})(\w{1})$/,
                    process: function(colorString) {
                        return [parseInt(colorString[1] + colorString[1], 16), parseInt(colorString[2] + colorString[2], 16), parseInt(colorString[3] + colorString[3], 16)]
                    }
                }, {
                    re: /^hsv\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
                    process: function(colorString) {
                        var h = parseInt(colorString[1], 10),
                            s = parseInt(colorString[2], 10),
                            v = parseInt(colorString[3], 10),
                            rgb = hsvToRgb(h, s, v);
                        return [rgb[0], rgb[1], rgb[2], 1, [h, s, v]]
                    }
                }, {
                    re: /^hsl\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
                    process: function(colorString) {
                        var h = parseInt(colorString[1], 10),
                            s = parseInt(colorString[2], 10),
                            l = parseInt(colorString[3], 10),
                            rgb = hslToRgb(h, s, l);
                        return [rgb[0], rgb[1], rgb[2], 1, null, [h, s, l]]
                    }
                }];
        function Color(value) {
            this.baseColor = value;
            var color;
            if (value) {
                color = String(value).toLowerCase().replace(/ /g, '');
                color = standardColorNames[color] ? '#' + standardColorNames[color] : color;
                color = parseColor(color)
            }
            if (!color)
                this.colorIsInvalid = true;
            color = color || {};
            this.r = normalize(color[0]);
            this.g = normalize(color[1]);
            this.b = normalize(color[2]);
            this.a = normalize(color[3], 1, 1);
            if (color[4])
                this.hsv = {
                    h: color[4][0],
                    s: color[4][1],
                    v: color[4][2]
                };
            else
                this.hsv = toHsvFromRgb(this.r, this.g, this.b);
            if (color[5])
                this.hsl = {
                    h: color[5][0],
                    s: color[5][1],
                    l: color[5][2]
                };
            else
                this.hsl = toHslFromRgb(this.r, this.g, this.b)
        }
        function parseColor(color) {
            if (color === "transparent")
                return [0, 0, 0, 0];
            var result,
                i = 0,
                ii = standardColorTypes.length,
                str;
            for (; i < ii; ++i) {
                str = standardColorTypes[i].re.exec(color);
                if (str)
                    return standardColorTypes[i].process(str)
            }
            return null
        }
        function normalize(colorComponent, def, max) {
            def = def || 0;
            max = max || 255;
            return colorComponent < 0 || isNaN(colorComponent) ? def : colorComponent > max ? max : colorComponent
        }
        function toHexFromRgb(r, g, b) {
            return '#' + (0X01000000 | r << 16 | g << 8 | b).toString(16).slice(1)
        }
        function toHsvFromRgb(r, g, b) {
            var max = Math.max(r, g, b),
                min = Math.min(r, g, b),
                delta = max - min,
                H,
                S,
                V;
            V = max;
            S = max === 0 ? 0 : 1 - min / max;
            if (max === min)
                H = 0;
            else
                switch (max) {
                    case r:
                        H = 60 * ((g - b) / delta);
                        if (g < b)
                            H = H + 360;
                        break;
                    case g:
                        H = 60 * ((b - r) / delta) + 120;
                        break;
                    case b:
                        H = 60 * ((r - g) / delta) + 240;
                        break
                }
            S *= 100;
            V *= 100 / 255;
            return {
                    h: Math.round(H),
                    s: Math.round(S),
                    v: Math.round(V)
                }
        }
        function hsvToRgb(h, s, v) {
            var Vdec,
                Vinc,
                Vmin,
                Hi,
                a,
                r,
                g,
                b;
            Hi = Math.floor(h / 60);
            Vmin = (100 - s) * v / 100;
            a = (v - Vmin) * (h % 60 / 60);
            Vinc = Vmin + a;
            Vdec = v - a;
            switch (Hi) {
                case 0:
                    r = v;
                    g = Vinc;
                    b = Vmin;
                    break;
                case 1:
                    r = Vdec;
                    g = v;
                    b = Vmin;
                    break;
                case 2:
                    r = Vmin;
                    g = v;
                    b = Vinc;
                    break;
                case 3:
                    r = Vmin;
                    g = Vdec;
                    b = v;
                    break;
                case 4:
                    r = Vinc;
                    g = Vmin;
                    b = v;
                    break;
                case 5:
                    r = v;
                    g = Vmin;
                    b = Vdec;
                    break
            }
            return [Math.round(r * 2.55), Math.round(g * 2.55), Math.round(b * 2.55)]
        }
        function calculateHue(r, g, b, delta) {
            var max = Math.max(r, g, b);
            switch (max) {
                case r:
                    return (g - b) / delta + (g < b ? 6 : 0);
                case g:
                    return (b - r) / delta + 2;
                case b:
                    return (r - g) / delta + 4
            }
        }
        function toHslFromRgb(r, g, b) {
            r = convertTo01Bounds(r, 255);
            g = convertTo01Bounds(g, 255);
            b = convertTo01Bounds(b, 255);
            var max = Math.max(r, g, b),
                min = Math.min(r, g, b),
                maxMinSumm = max + min,
                h,
                s,
                l = maxMinSumm / 2;
            if (max === min)
                h = s = 0;
            else {
                var delta = max - min;
                if (l > 0.5)
                    s = delta / (2 - maxMinSumm);
                else
                    s = delta / maxMinSumm;
                h = calculateHue(r, g, b, delta);
                h /= 6
            }
            return {
                    h: _round(h * 360),
                    s: _round(s * 100),
                    l: _round(l * 100)
                }
        }
        function makeTc(colorPart, h) {
            var Tc = h;
            if (colorPart === "r")
                Tc = h + 1 / 3;
            if (colorPart === "b")
                Tc = h - 1 / 3;
            return Tc
        }
        function modifyTc(Tc) {
            if (Tc < 0)
                Tc += 1;
            if (Tc > 1)
                Tc -= 1;
            return Tc
        }
        function hueToRgb(p, q, Tc) {
            Tc = modifyTc(Tc);
            if (Tc < 1 / 6)
                return p + (q - p) * 6 * Tc;
            if (Tc < 1 / 2)
                return q;
            if (Tc < 2 / 3)
                return p + (q - p) * (2 / 3 - Tc) * 6;
            return p
        }
        function hslToRgb(h, s, l) {
            var r,
                g,
                b,
                h = convertTo01Bounds(h, 360),
                s = convertTo01Bounds(s, 100),
                l = convertTo01Bounds(l, 100);
            if (s === 0)
                r = g = b = l;
            else {
                var q = l < 0.5 ? l * (1 + s) : l + s - l * s,
                    p = 2 * l - q;
                r = hueToRgb(p, q, makeTc("r", h));
                g = hueToRgb(p, q, makeTc("g", h));
                b = hueToRgb(p, q, makeTc("b", h))
            }
            return [_round(r * 255), _round(g * 255), _round(b * 255)]
        }
        function convertTo01Bounds(n, max) {
            n = Math.min(max, Math.max(0, parseFloat(n)));
            if (Math.abs(n - max) < 0.000001)
                return 1;
            return n % max / parseFloat(max)
        }
        function isIntegerBtwMinAndMax(number, min, max) {
            min = min || 0;
            max = max || 255;
            if (number % 1 !== 0 || number < min || number > max || typeof number !== 'number' || isNaN(number))
                return false;
            return true
        }
        var _round = Math.round;
        Color.prototype = {
            constructor: Color,
            highlight: function(step) {
                step = step || 10;
                return this.alter(step).toHex()
            },
            darken: function(step) {
                step = step || 10;
                return this.alter(-step).toHex()
            },
            alter: function(step) {
                var result = new Color;
                result.r = normalize(this.r + step);
                result.g = normalize(this.g + step);
                result.b = normalize(this.b + step);
                return result
            },
            blend: function(blendColor, opacity) {
                var other = blendColor instanceof Color ? blendColor : new Color(blendColor),
                    result = new Color;
                result.r = normalize(_round(this.r * (1 - opacity) + other.r * opacity));
                result.g = normalize(_round(this.g * (1 - opacity) + other.g * opacity));
                result.b = normalize(_round(this.b * (1 - opacity) + other.b * opacity));
                return result
            },
            toHex: function() {
                return toHexFromRgb(this.r, this.g, this.b)
            },
            getPureColor: function() {
                var rgb = hsvToRgb(this.hsv.h, 100, 100);
                return new Color("rgb(" + rgb.join(",") + ")")
            },
            isValidHex: function(hex) {
                return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex)
            },
            isValidRGB: function(r, g, b) {
                if (!isIntegerBtwMinAndMax(r) || !isIntegerBtwMinAndMax(g) || !isIntegerBtwMinAndMax(b))
                    return false;
                return true
            },
            isValidAlpha: function(a) {
                if (isNaN(a) || a < 0 || a > 1 || typeof a !== 'number')
                    return false;
                return true
            },
            colorIsInvalid: false
        };
        DX.Color = Color
    })(DevExpress);
    /*! Module core, file localization.js */
    (function($, DX, undefined) {
        Globalize.localize = function(key, cultureSelector) {
            var neutral = (cultureSelector || this.cultureSelector || "").substring(0, 2);
            return this.findClosestCulture(cultureSelector).messages[key] || this.findClosestCulture(neutral).messages[key] || this.cultures["default"].messages[key]
        };
        var localization = function() {
                var newMessages = {};
                return {
                        setup: function(localizablePrefix) {
                            this.localizeString = function(text) {
                                var regex = new RegExp("(^|[^a-zA-Z_0-9" + localizablePrefix + "-]+)(" + localizablePrefix + "{1,2})([a-zA-Z_0-9-]+)", "g"),
                                    escapeString = localizablePrefix + localizablePrefix;
                                return text.replace(regex, function(str, prefix, escape, localizationKey) {
                                        var result = prefix + localizablePrefix + localizationKey;
                                        if (escape !== escapeString)
                                            if (Globalize.cultures["default"].messages[localizationKey])
                                                result = prefix + Globalize.localize(localizationKey);
                                            else
                                                newMessages[localizationKey] = DX.inflector.humanize(localizationKey);
                                        return result
                                    })
                            }
                        },
                        localizeNode: function(node) {
                            var that = this;
                            $(node).each(function(index, nodeItem) {
                                if (!nodeItem.nodeType)
                                    return;
                                if (nodeItem.nodeType === 3)
                                    nodeItem.nodeValue = that.localizeString(nodeItem.nodeValue);
                                else {
                                    $.each(nodeItem.attributes || [], function(index, attr) {
                                        if (typeof attr.value === "string") {
                                            var localizedValue = that.localizeString(attr.value);
                                            if (attr.value !== localizedValue)
                                                attr.value = localizedValue
                                        }
                                    });
                                    $(nodeItem).contents().each(function(index, node) {
                                        that.localizeNode(node)
                                    })
                                }
                            })
                        },
                        getDictionary: function(onlyNew) {
                            if (onlyNew)
                                return newMessages;
                            return $.extend({}, newMessages, Globalize.cultures["default"].messages)
                        }
                    }
            }();
        localization.setup("@");
        DX.localization = localization
    })(jQuery, DevExpress);
    /*! Module core, file localization.en.js */
    Globalize.addCultureInfo("default", {messages: {
            Yes: "Yes",
            No: "No",
            Cancel: "Cancel",
            Clear: "Clear",
            Done: "Done",
            Loading: "Loading...",
            Select: "Select...",
            Search: "Search",
            Back: "Back",
            OK: "OK",
            "dxLookup-searchPlaceholder": "Minimum character number: {0}",
            "dxCollectionContainerWidget-noDataText": "No data to display",
            "dxList-pullingDownText": "Pull down to refresh...",
            "dxList-pulledDownText": "Release to refresh...",
            "dxList-refreshingText": "Refreshing...",
            "dxList-pageLoadingText": "Loading...",
            "dxList-nextButtonText": "More",
            "dxListEditDecorator-delete": "Delete",
            "dxListEditDecorator-more": "More",
            "dxScrollView-pullingDownText": "Pull down to refresh...",
            "dxScrollView-pulledDownText": "Release to refresh...",
            "dxScrollView-refreshingText": "Refreshing...",
            "dxScrollView-reachBottomText": "Loading...",
            "dxSwitch-onText": "ON",
            "dxSwitch-offText": "OFF",
            "dxDateBox-simulatedDataPickerTitleTime": "Select time",
            "dxDateBox-simulatedDataPickerTitleDate": "Select date",
            "dxDateBox-simulatedDataPickerTitleDateTime": "Select date and time",
            "dxDataGrid-columnChooserTitle": "Column Chooser",
            "dxDataGrid-columnChooserEmptyText": "Drag a column here to hide it",
            "dxDataGrid-groupContinuesMessage": "Continues on the next page",
            "dxDataGrid-groupContinuedMessage": "Continued from the previous page",
            "dxDataGrid-editingEditRow": "Edit",
            "dxDataGrid-editingSaveRowChanges": "Save",
            "dxDataGrid-editingCancelRowChanges": "Cancel",
            "dxDataGrid-editingDeleteRow": "Delete",
            "dxDataGrid-editingUndeleteRow": "Undelete",
            "dxDataGrid-editingConfirmDeleteMessage": "Are you sure you want to delete this record?",
            "dxDataGrid-editingConfirmDeleteTitle": "",
            "dxDataGrid-groupPanelEmptyText": "Drag a column header here to group by that column",
            "dxDataGrid-noDataText": "No data",
            "dxDataGrid-searchPanelPlaceholder": "Search...",
            "dxDataGrid-filterRowShowAllText": "(All)",
            "dxDataGrid-filterRowResetOperationText": "Reset",
            "dxDataGrid-filterRowOperationEquals": "Equals",
            "dxDataGrid-filterRowOperationNotEquals": "Does not equal",
            "dxDataGrid-filterRowOperationLess": "Less than",
            "dxDataGrid-filterRowOperationLessOrEquals": "Less than or equal to",
            "dxDataGrid-filterRowOperationGreater": "Greater than",
            "dxDataGrid-filterRowOperationGreaterOrEquals": "Greater than or equal to",
            "dxDataGrid-filterRowOperationStartsWith": "Starts with",
            "dxDataGrid-filterRowOperationContains": "Contains",
            "dxDataGrid-filterRowOperationNotContains": "Does not contain",
            "dxDataGrid-filterRowOperationEndsWith": "Ends with",
            "dxDataGrid-trueText": "true",
            "dxDataGrid-falseText": "false",
            "dxDataGrid-sortingAscendingText": "Sort Ascending",
            "dxDataGrid-sortingDescendingText": "Sort Descending",
            "dxDataGrid-sortingClearText": "Clear Sorting"
        }});
    /*! Module core, file data.js */
    (function($, DX, undefined) {
        var HAS_KO = DX.support.hasKo;
        var bracketsToDots = function(expr) {
                return expr.replace(/\[/g, ".").replace(/\]/g, "")
            };
        var unwrapObservable = function(value) {
                if (HAS_KO)
                    return ko.utils.unwrapObservable(value);
                return value
            };
        var isObservable = function(value) {
                return HAS_KO && ko.isObservable(value)
            };
        var readPropValue = function(obj, propName) {
                if (propName === "this")
                    return obj;
                return obj[propName]
            };
        var assignPropValue = function(obj, propName, value) {
                if (propName === "this")
                    throw Error("Cannot assign to self");
                var propValue = obj[propName];
                if (isObservable(propValue))
                    propValue(value);
                else
                    obj[propName] = value
            };
        var compileGetter = function(expr) {
                if (arguments.length > 1)
                    expr = $.makeArray(arguments);
                if (!expr || expr === "this")
                    return function(obj) {
                            return obj
                        };
                if ($.isFunction(expr))
                    return expr;
                if ($.isArray(expr))
                    return combineGetters(expr);
                expr = bracketsToDots(expr);
                var path = expr.split(".");
                return function(obj, options) {
                        options = options || {};
                        var current = unwrapObservable(obj);
                        $.each(path, function() {
                            if (!current)
                                return false;
                            var next = unwrapObservable(current[this]);
                            if ($.isFunction(next) && !options.functionsAsIs)
                                next = next.call(current);
                            current = next
                        });
                        return current
                    }
            };
        var combineGetters = function(getters) {
                var compiledGetters = {};
                $.each(getters, function() {
                    compiledGetters[this] = compileGetter(this)
                });
                return function(obj, options) {
                        var result = {};
                        $.each(compiledGetters, function(name) {
                            var value = this(obj, options),
                                current,
                                path,
                                last,
                                i;
                            if (value === undefined)
                                return;
                            current = result;
                            path = name.split(".");
                            last = path.length - 1;
                            for (i = 0; i < last; i++)
                                current = current[path[i]] = {};
                            current[path[i]] = value
                        });
                        return result
                    }
            };
        var compileSetter = function(expr) {
                expr = expr || "this";
                expr = bracketsToDots(expr);
                var pos = expr.lastIndexOf("."),
                    targetGetter = compileGetter(expr.substr(0, pos)),
                    targetPropName = expr.substr(1 + pos);
                return function(obj, value, options) {
                        options = options || {};
                        var target = targetGetter(obj, {functionsAsIs: options.functionsAsIs}),
                            prevTargetValue = readPropValue(target, targetPropName);
                        if (!options.functionsAsIs && $.isFunction(prevTargetValue) && !isObservable(prevTargetValue))
                            target[targetPropName](value);
                        else {
                            prevTargetValue = unwrapObservable(prevTargetValue);
                            if (options.merge && $.isPlainObject(value) && (prevTargetValue === undefined || $.isPlainObject(prevTargetValue)) && !(value instanceof $.Event)) {
                                if (!prevTargetValue)
                                    assignPropValue(target, targetPropName, {});
                                DX.utils.deepExtendArraySafe(unwrapObservable(readPropValue(target, targetPropName)), value)
                            }
                            else
                                assignPropValue(target, targetPropName, value)
                        }
                    }
            };
        var normalizeBinaryCriterion = function(crit) {
                return [crit[0], crit.length < 3 ? "=" : crit[1].toLowerCase(), crit.length < 2 ? true : crit[crit.length - 1]]
            };
        var normalizeSortingInfo = function(info) {
                if (!$.isArray(info))
                    info = [info];
                return $.map(info, function(i) {
                        return {
                                selector: $.isFunction(i) || typeof i === "string" ? i : i.getter || i.field || i.selector,
                                desc: !!(i.desc || String(i.dir).charAt(0).toLowerCase() === "d")
                            }
                    })
            };
        var Guid = DX.Class.inherit({
                ctor: function(value) {
                    if (value)
                        value = String(value);
                    this._value = this._normalize(value || this._generate())
                },
                _normalize: function(value) {
                    value = value.replace(/[^a-f0-9]/ig, "").toLowerCase();
                    while (value.length < 32)
                        value += "0";
                    return [value.substr(0, 8), value.substr(8, 4), value.substr(12, 4), value.substr(16, 4), value.substr(20, 12)].join("-")
                },
                _generate: function() {
                    var value = "";
                    for (var i = 0; i < 32; i++)
                        value += Math.round(Math.random() * 15).toString(16);
                    return value
                },
                toString: function() {
                    return this._value
                },
                valueOf: function() {
                    return this._value
                },
                toJSON: function() {
                    return this._value
                }
            });
        var toComparable = function(value, caseSensitive) {
                if (value instanceof Date)
                    return value.getTime();
                if (value instanceof Guid)
                    return value.valueOf();
                if (!caseSensitive && typeof value === "string")
                    return value.toLowerCase();
                return value
            };
        var keysEqual = function(keyExpr, key1, key2) {
                if ($.isArray(keyExpr)) {
                    var names = $.map(key1, function(v, k) {
                            return k
                        }),
                        name;
                    for (var i = 0; i < names.length; i++) {
                        name = names[i];
                        if (toComparable(key1[name], true) != toComparable(key2[name], true))
                            return false
                    }
                    return true
                }
                return toComparable(key1, true) == toComparable(key2, true)
            };
        var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        var base64_encode = function(input) {
                if (!$.isArray(input))
                    input = stringToByteArray(String(input));
                var result = "";
                for (var i = 0; i < input.length; i += 3) {
                    var octet1 = input[i],
                        octet2 = input[i + 1],
                        octet3 = input[i + 2];
                    result += $.map([octet1 >> 2, (octet1 & 3) << 4 | octet2 >> 4, isNaN(octet2) ? 64 : (octet2 & 15) << 2 | octet3 >> 6, isNaN(octet3) ? 64 : octet3 & 63], function(item) {
                        return BASE64_CHARS.charAt(item)
                    }).join("")
                }
                return result
            };
        var stringToByteArray = function(str) {
                var bytes = [],
                    code,
                    i;
                for (i = 0; i < str.length; i++) {
                    code = str.charCodeAt(i);
                    if (code < 128)
                        bytes.push(code);
                    else if (code < 2048)
                        bytes.push(192 + (code >> 6), 128 + (code & 63));
                    else if (code < 65536)
                        bytes.push(224 + (code >> 12), 128 + (code >> 6 & 63), 128 + (code & 63));
                    else if (code < 2097152)
                        bytes.push(240 + (code >> 18), 128 + (code >> 12 & 63), 128 + (code >> 6 & 63), 128 + (code & 63))
                }
                return bytes
            };
        var errorMessageFromXhr = function() {
                var textStatusMessages = {
                        timeout: "Network connection timeout",
                        error: "Unspecified network error",
                        parsererror: "Unexpected server response"
                    };
                var textStatusDetails = {
                        timeout: "possible causes: the remote host is not accessible, overloaded or is not included into the domain white-list when being run in the native container",
                        error: "if the remote host is located on another domain, make sure it properly supports cross-origin resource sharing (CORS), or use the JSONP approach instead",
                        parsererror: "the remote host did not respond with valid JSON data"
                    };
                var explainTextStatus = function(textStatus) {
                        var result = textStatusMessages[textStatus];
                        if (!result)
                            return textStatus;
                        result += " (" + textStatusDetails[textStatus] + ")";
                        return result
                    };
                return function(xhr, textStatus) {
                        if (xhr.status < 400)
                            return explainTextStatus(textStatus);
                        return xhr.statusText
                    }
            }();
        var data = DX.data = {
                utils: {
                    compileGetter: compileGetter,
                    compileSetter: compileSetter,
                    normalizeBinaryCriterion: normalizeBinaryCriterion,
                    normalizeSortingInfo: normalizeSortingInfo,
                    toComparable: toComparable,
                    keysEqual: keysEqual,
                    errorMessageFromXhr: errorMessageFromXhr
                },
                Guid: Guid,
                base64_encode: base64_encode,
                queryImpl: {},
                queryAdapters: {},
                query: function() {
                    var impl = $.isArray(arguments[0]) ? "array" : "remote";
                    return data.queryImpl[impl].apply(this, arguments)
                },
                errorHandler: null,
                _handleError: function(error) {
                    if (window.console)
                        console.warn("[DevExpress.data]: " + error);
                    if (data.errorHandler)
                        data.errorHandler(error)
                }
            }
    })(jQuery, DevExpress);
    /*! Module core, file data.query.array.js */
    (function($, DX, undefined) {
        var Class = DX.Class,
            data = DX.data,
            queryImpl = data.queryImpl,
            compileGetter = data.utils.compileGetter,
            toComparable = data.utils.toComparable;
        var Iterator = Class.inherit({
                toArray: function() {
                    var result = [];
                    this.reset();
                    while (this.next())
                        result.push(this.current());
                    return result
                },
                countable: function() {
                    return false
                }
            });
        var ArrayIterator = Iterator.inherit({
                ctor: function(array) {
                    this.array = array;
                    this.index = -1
                },
                next: function() {
                    if (this.index + 1 < this.array.length) {
                        this.index++;
                        return true
                    }
                    return false
                },
                current: function() {
                    return this.array[this.index]
                },
                reset: function() {
                    this.index = -1
                },
                toArray: function() {
                    return this.array.slice(0)
                },
                countable: function() {
                    return true
                },
                count: function() {
                    return this.array.length
                }
            });
        var WrappedIterator = Iterator.inherit({
                ctor: function(iter) {
                    this.iter = iter
                },
                next: function() {
                    return this.iter.next()
                },
                current: function() {
                    return this.iter.current()
                },
                reset: function() {
                    return this.iter.reset()
                }
            });
        var MapIterator = WrappedIterator.inherit({
                ctor: function(iter, mapper) {
                    this.callBase(iter);
                    this.index = -1;
                    this.mapper = mapper
                },
                current: function() {
                    return this.mapper(this.callBase(), this.index)
                },
                next: function() {
                    var hasNext = this.callBase();
                    if (hasNext)
                        this.index++;
                    return hasNext
                }
            });
        var SortIterator = Iterator.inherit({
                ctor: function(iter, getter, desc) {
                    if (!(iter instanceof MapIterator))
                        iter = new MapIterator(iter, this._wrap);
                    this.iter = iter;
                    this.rules = [{
                            getter: getter,
                            desc: desc
                        }]
                },
                thenBy: function(getter, desc) {
                    var result = new SortIterator(this.sortedIter || this.iter, getter, desc);
                    if (!this.sortedIter)
                        result.rules = this.rules.concat(result.rules);
                    return result
                },
                next: function() {
                    this._ensureSorted();
                    return this.sortedIter.next()
                },
                current: function() {
                    this._ensureSorted();
                    return this.sortedIter.current()
                },
                reset: function() {
                    delete this.sortedIter
                },
                countable: function() {
                    return this.sortedIter || this.iter.countable()
                },
                count: function() {
                    if (this.sortedIter)
                        return this.sortedIter.count();
                    return this.iter.count()
                },
                _ensureSorted: function() {
                    if (this.sortedIter)
                        return;
                    $.each(this.rules, function() {
                        this.getter = compileGetter(this.getter)
                    });
                    this.sortedIter = new MapIterator(new ArrayIterator(this.iter.toArray().sort($.proxy(this._compare, this))), this._unwrap)
                },
                _wrap: function(record, index) {
                    return {
                            index: index,
                            value: record
                        }
                },
                _unwrap: function(wrappedItem) {
                    return wrappedItem.value
                },
                _compare: function(x, y) {
                    var xIndex = x.index,
                        yIndex = y.index;
                    x = x.value;
                    y = y.value;
                    if (x === y)
                        return xIndex - yIndex;
                    for (var i = 0, rulesCount = this.rules.length; i < rulesCount; i++) {
                        var rule = this.rules[i],
                            xValue = toComparable(rule.getter(x)),
                            yValue = toComparable(rule.getter(y)),
                            factor = rule.desc ? -1 : 1;
                        if (xValue < yValue)
                            return -factor;
                        if (xValue > yValue)
                            return factor;
                        if (xValue !== yValue)
                            return !xValue ? -factor : factor
                    }
                    return xIndex - yIndex
                }
            });
        var compileCriteria = function() {
                var compileGroup = function(crit) {
                        var operands = [],
                            bag = ["return function(d) { return "],
                            index = 0,
                            pushAnd = false;
                        $.each(crit, function() {
                            if ($.isArray(this) || $.isFunction(this)) {
                                if (pushAnd)
                                    bag.push(" && ");
                                operands.push(compileCriteria(this));
                                bag.push("op[", index, "](d)");
                                index++;
                                pushAnd = true
                            }
                            else {
                                bag.push(/and|&/i.test(this) ? " && " : " || ");
                                pushAnd = false
                            }
                        });
                        bag.push(" }");
                        return new Function("op", bag.join(""))(operands)
                    };
                var toString = function(value) {
                        return DX.utils.isDefined(value) ? value.toString() : ''
                    };
                var compileBinary = function(crit) {
                        crit = data.utils.normalizeBinaryCriterion(crit);
                        var getter = compileGetter(crit[0]),
                            op = crit[1],
                            value = crit[2];
                        value = toComparable(value);
                        switch (op.toLowerCase()) {
                            case"=":
                                return compileEquals(getter, value);
                            case"<>":
                                return compileEquals(getter, value, true);
                            case">":
                                return function(obj) {
                                        return toComparable(getter(obj)) > value
                                    };
                            case"<":
                                return function(obj) {
                                        return toComparable(getter(obj)) < value
                                    };
                            case">=":
                                return function(obj) {
                                        return toComparable(getter(obj)) >= value
                                    };
                            case"<=":
                                return function(obj) {
                                        return toComparable(getter(obj)) <= value
                                    };
                            case"startswith":
                                return function(obj) {
                                        return toComparable(toString(getter(obj))).indexOf(value) === 0
                                    };
                            case"endswith":
                                return function(obj) {
                                        var getterValue = toComparable(toString(getter(obj)));
                                        return getterValue.lastIndexOf(value) === getterValue.length - toString(value).length
                                    };
                            case"contains":
                                return function(obj) {
                                        return toComparable(toString(getter(obj))).indexOf(value) > -1
                                    };
                            case"notcontains":
                                return function(obj) {
                                        return toComparable(toString(getter(obj))).indexOf(value) === -1
                                    }
                        }
                        throw Error("Unknown filter operation: " + op);
                    };
                function compileEquals(getter, value, negate) {
                    return function(obj) {
                            obj = toComparable(getter(obj));
                            var result = useStrictComparison(value) ? obj === value : obj == value;
                            if (negate)
                                result = !result;
                            return result
                        }
                }
                function useStrictComparison(value) {
                    return value === "" || value === 0 || value === null || value === false || value === undefined
                }
                return function(crit) {
                        if ($.isFunction(crit))
                            return crit;
                        if ($.isArray(crit[0]))
                            return compileGroup(crit);
                        return compileBinary(crit)
                    }
            }();
        var FilterIterator = WrappedIterator.inherit({
                ctor: function(iter, criteria) {
                    this.callBase(iter);
                    this.criteria = compileCriteria(criteria)
                },
                next: function() {
                    while (this.iter.next())
                        if (this.criteria(this.current()))
                            return true;
                    return false
                }
            });
        var GroupIterator = Iterator.inherit({
                ctor: function(iter, getter) {
                    this.iter = iter;
                    this.getter = getter
                },
                next: function() {
                    this._ensureGrouped();
                    return this.groupedIter.next()
                },
                current: function() {
                    this._ensureGrouped();
                    return this.groupedIter.current()
                },
                reset: function() {
                    delete this.groupedIter
                },
                countable: function() {
                    return !!this.groupedIter
                },
                count: function() {
                    return this.groupedIter.count()
                },
                _ensureGrouped: function() {
                    if (this.groupedIter)
                        return;
                    var hash = {},
                        keys = [],
                        iter = this.iter,
                        getter = compileGetter(this.getter);
                    iter.reset();
                    while (iter.next()) {
                        var current = iter.current(),
                            key = getter(current);
                        if (key in hash)
                            hash[key].push(current);
                        else {
                            hash[key] = [current];
                            keys.push(key)
                        }
                    }
                    this.groupedIter = new ArrayIterator($.map(keys, function(key) {
                        return {
                                key: key,
                                items: hash[key]
                            }
                    }))
                }
            });
        var SelectIterator = WrappedIterator.inherit({
                ctor: function(iter, getter) {
                    this.callBase(iter);
                    this.getter = compileGetter(getter)
                },
                current: function() {
                    return this.getter(this.callBase())
                },
                countable: function() {
                    return this.iter.countable()
                },
                count: function() {
                    return this.iter.count()
                }
            });
        var SliceIterator = WrappedIterator.inherit({
                ctor: function(iter, skip, take) {
                    this.callBase(iter);
                    this.skip = Math.max(0, skip);
                    this.take = Math.max(0, take);
                    this.pos = 0
                },
                next: function() {
                    if (this.pos >= this.skip + this.take)
                        return false;
                    while (this.pos < this.skip && this.iter.next())
                        this.pos++;
                    this.pos++;
                    return this.iter.next()
                },
                reset: function() {
                    this.callBase();
                    this.pos = 0
                },
                countable: function() {
                    return this.iter.countable()
                },
                count: function() {
                    return Math.min(this.iter.count() - this.skip, this.take)
                }
            });
        queryImpl.array = function(iter, queryOptions) {
            queryOptions = queryOptions || {};
            if (!(iter instanceof Iterator))
                iter = new ArrayIterator(iter);
            var handleError = function(error) {
                    var handler = queryOptions.errorHandler;
                    if (handler)
                        handler(error);
                    data._handleError(error)
                };
            var aggregate = function(seed, step, finalize) {
                    var d = $.Deferred().fail(handleError);
                    try {
                        iter.reset();
                        if (arguments.length < 2) {
                            step = arguments[0];
                            seed = iter.next() ? iter.current() : undefined
                        }
                        var accumulator = seed;
                        while (iter.next())
                            accumulator = step(accumulator, iter.current());
                        d.resolve(finalize ? finalize(accumulator) : accumulator)
                    }
                    catch(x) {
                        d.reject(x)
                    }
                    return d.promise()
                };
            var select = function(getter) {
                    if (!$.isFunction(getter) && !$.isArray(getter))
                        getter = $.makeArray(arguments);
                    return chainQuery(new SelectIterator(iter, getter))
                };
            var selectProp = function(name) {
                    return select(compileGetter(name))
                };
            var chainQuery = function(iter) {
                    return queryImpl.array(iter, queryOptions)
                };
            return {
                    toArray: function() {
                        return iter.toArray()
                    },
                    enumerate: function() {
                        var d = $.Deferred().fail(handleError);
                        try {
                            d.resolve(iter.toArray())
                        }
                        catch(x) {
                            d.reject(x)
                        }
                        return d.promise()
                    },
                    sortBy: function(getter, desc) {
                        return chainQuery(new SortIterator(iter, getter, desc))
                    },
                    thenBy: function(getter, desc) {
                        if (iter instanceof SortIterator)
                            return chainQuery(iter.thenBy(getter, desc));
                        throw Error();
                    },
                    filter: function(criteria) {
                        if (!$.isArray(criteria))
                            criteria = $.makeArray(arguments);
                        return chainQuery(new FilterIterator(iter, criteria))
                    },
                    slice: function(skip, take) {
                        if (take === undefined)
                            take = Number.MAX_VALUE;
                        return chainQuery(new SliceIterator(iter, skip, take))
                    },
                    select: select,
                    groupBy: function(getter) {
                        return chainQuery(new GroupIterator(iter, getter))
                    },
                    aggregate: aggregate,
                    count: function() {
                        if (iter.countable()) {
                            var d = $.Deferred().fail(handleError);
                            try {
                                d.resolve(iter.count())
                            }
                            catch(x) {
                                d.reject(x)
                            }
                            return d.promise()
                        }
                        return aggregate(0, function(count) {
                                return 1 + count
                            })
                    },
                    sum: function(getter) {
                        if (getter)
                            return selectProp(getter).sum();
                        return aggregate(0, function(sum, item) {
                                return sum + item
                            })
                    },
                    min: function(getter) {
                        if (getter)
                            return selectProp(getter).min();
                        return aggregate(function(min, item) {
                                return item < min ? item : min
                            })
                    },
                    max: function(getter) {
                        if (getter)
                            return selectProp(getter).max();
                        return aggregate(function(max, item) {
                                return item > max ? item : max
                            })
                    },
                    avg: function(getter) {
                        if (getter)
                            return selectProp(getter).avg();
                        var count = 0;
                        return aggregate(0, function(sum, item) {
                                count++;
                                return sum + item
                            }, function(sum) {
                                return count ? sum / count : undefined
                            })
                    }
                }
        }
    })(jQuery, DevExpress);
    /*! Module core, file data.query.remote.js */
    (function($, DX, undefined) {
        var data = DX.data,
            queryImpl = data.queryImpl;
        queryImpl.remote = function(url, queryOptions, tasks) {
            tasks = tasks || [];
            queryOptions = queryOptions || {};
            var createTask = function(name, args) {
                    return {
                            name: name,
                            args: args
                        }
                };
            var exec = function(executorTask) {
                    var d = $.Deferred(),
                        adapterFactory,
                        adapter,
                        taskQueue,
                        currentTask;
                    var rejectWithNotify = function(error) {
                            var handler = queryOptions.errorHandler;
                            if (handler)
                                handler(error);
                            data._handleError(error);
                            d.reject(error)
                        };
                    try {
                        adapterFactory = queryOptions.adapter || "odata";
                        if (!$.isFunction(adapterFactory))
                            adapterFactory = data.queryAdapters[adapterFactory];
                        adapter = adapterFactory(queryOptions);
                        taskQueue = [].concat(tasks).concat(executorTask);
                        while (taskQueue.length) {
                            currentTask = taskQueue[0];
                            if (String(currentTask.name) !== "enumerate")
                                if (!adapter[currentTask.name] || adapter[currentTask.name].apply(adapter, currentTask.args) === false)
                                    break;
                            taskQueue.shift()
                        }
                        adapter.exec(url).done(function(result, extra) {
                            if (!taskQueue.length)
                                d.resolve(result, extra);
                            else {
                                var clientChain = queryImpl.array(result, {errorHandler: queryOptions.errorHandler});
                                $.each(taskQueue, function() {
                                    clientChain = clientChain[this.name].apply(clientChain, this.args)
                                });
                                clientChain.done($.proxy(d.resolve, d)).fail($.proxy(d.reject, d))
                            }
                        }).fail(rejectWithNotify)
                    }
                    catch(x) {
                        rejectWithNotify(x)
                    }
                    return d.promise()
                };
            var query = {};
            $.each(["sortBy", "thenBy", "filter", "slice", "select", "groupBy"], function() {
                var name = this;
                query[name] = function() {
                    return queryImpl.remote(url, queryOptions, tasks.concat(createTask(name, arguments)))
                }
            });
            $.each(["count", "min", "max", "sum", "avg", "aggregate", "enumerate"], function() {
                var name = this;
                query[name] = function() {
                    return exec.call(this, createTask(name, arguments))
                }
            });
            return query
        }
    })(jQuery, DevExpress);
    /*! Module core, file data.odata.js */
    (function($, DX, undefined) {
        var data = DX.data,
            utils = DX.utils,
            Guid = data.Guid;
        var VERBOSE_DATE_REGEX = /^\/Date\((-?\d+)((\+|-)?(\d+)?)\)\/$/;
        var ISO8601_DATE_REGEX = /^(\d{4})(?:-?W(\d+)(?:-?(\d+)D?)?|(?:-(\d+))?-(\d+))(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?$/;
        var timezoneOffset = (new Date).getTimezoneOffset() * 60 * 1000;
        var JSON_VERBOSE_MIME_TYPE = "application/json;odata=verbose";
        var ajaxOptionsForRequest = function(request, requestOptions) {
                request = $.extend({
                    method: "get",
                    url: "",
                    params: {},
                    payload: null,
                    headers: {}
                }, request);
                requestOptions = requestOptions || {};
                var beforeSend = requestOptions.beforeSend;
                if (beforeSend)
                    beforeSend(request);
                var method = (request.method || "get").toLowerCase(),
                    isGet = method === "get",
                    useJsonp = isGet && requestOptions.jsonp,
                    params = $.extend({}, request.params),
                    ajaxData = isGet ? params : JSON.stringify(request.payload, function(key, value) {
                        if (this[key] instanceof Date)
                            return utils.formatIso8601Date(this[key]);
                        return value
                    }),
                    qs = !isGet && $.param(params),
                    url = request.url,
                    contentType = !isGet && JSON_VERBOSE_MIME_TYPE;
                if (qs)
                    url += (url.indexOf("?") > -1 ? "&" : "?") + qs;
                if (useJsonp)
                    ajaxData["$format"] = "json";
                return {
                        url: url,
                        data: ajaxData,
                        dataType: useJsonp ? "jsonp" : "json",
                        jsonp: useJsonp && "$callback",
                        type: method,
                        timeout: 30000,
                        headers: request.headers,
                        contentType: contentType,
                        accepts: {json: [JSON_VERBOSE_MIME_TYPE, "text/plain"].join()},
                        xhrFields: {withCredentials: requestOptions.withCredentials}
                    }
            };
        var sendRequest = function(request, requestOptions) {
                var d = $.Deferred();
                $.ajax(ajaxOptionsForRequest(request, requestOptions)).always(function(obj, textStatus) {
                    var tuplet = interpretJsonFormat(obj, textStatus),
                        error = tuplet.error,
                        data = tuplet.data,
                        nextUrl = tuplet.nextUrl,
                        extra;
                    if (error)
                        d.reject(error);
                    else if (requestOptions.countOnly)
                        d.resolve(tuplet.count);
                    else if (nextUrl)
                        sendRequest({url: nextUrl}, requestOptions).fail($.proxy(d.reject, d)).done(function(nextData) {
                            d.resolve(data.concat(nextData))
                        });
                    else {
                        if (isFinite(tuplet.count))
                            extra = {totalCount: tuplet.count};
                        d.resolve(data, extra)
                    }
                });
                return d.promise()
            };
        var formatDotNetError = function(errorObj) {
                var message,
                    currentError = errorObj;
                if ("message" in errorObj)
                    if (errorObj.message.value)
                        message = errorObj.message.value;
                    else
                        message = errorObj.message;
                while (currentError = currentError.innererror || currentError.internalexception) {
                    message = currentError.message;
                    if (currentError.internalexception && message.indexOf("inner exception") === -1)
                        break
                }
                return message
            };
        var errorFromResponse = function(obj, textStatus) {
                if (textStatus === "nocontent")
                    return null;
                var httpStatus = 200,
                    message = "Unknown error",
                    response = obj;
                if (textStatus !== "success") {
                    httpStatus = obj.status;
                    message = data.utils.errorMessageFromXhr(obj, textStatus);
                    try {
                        response = $.parseJSON(obj.responseText)
                    }
                    catch(x) {}
                }
                var errorObj = response && (response.error || response["odata.error"]);
                if (errorObj) {
                    message = formatDotNetError(errorObj) || message;
                    if (httpStatus === 200)
                        httpStatus = 500;
                    if (errorObj.code)
                        httpStatus = Number(errorObj.code);
                    return $.extend(Error(message), {
                            httpStatus: httpStatus,
                            errorDetails: errorObj
                        })
                }
                else if (httpStatus !== 200)
                    return $.extend(Error(message), {httpStatus: httpStatus})
            };
        var interpretJsonFormat = function(obj, textStatus) {
                var error = errorFromResponse(obj, textStatus);
                if (error)
                    return {error: error};
                if (!$.isPlainObject(obj))
                    return {data: obj};
                if ("d" in obj && (utils.isArray(obj.d) || utils.isObject(obj.d)))
                    return interpretVerboseJsonFormat(obj, textStatus);
                return interpretLightJsonFormat(obj, textStatus)
            };
        var interpretVerboseJsonFormat = function(obj, textStatus) {
                var data = obj.d;
                if (!data)
                    return {error: Error("Malformed or unsupported JSON response received")};
                data = data.results || data;
                traverse(data, function(obj, key) {
                    var matches = obj[key].match(VERBOSE_DATE_REGEX);
                    if (matches)
                        obj[key] = new Date(timezoneOffset + Number(matches[1]) + matches[2] * 60000)
                });
                return {
                        data: data,
                        nextUrl: obj.d.__next,
                        count: parseInt(obj.d.__count, 10)
                    }
            };
        var interpretLightJsonFormat = function(obj, textStatus) {
                var data = obj.value || obj;
                if (!data)
                    return {error: Error("Malformed or unsupported JSON response received")};
                traverse(data, function(obj, key) {
                    if (ISO8601_DATE_REGEX.test(obj[key]))
                        obj[key] = new Date(timezoneOffset + utils.parseIso8601Date(obj[key]).valueOf())
                });
                return {
                        data: data,
                        nextUrl: obj["odata.nextLink"],
                        count: parseInt(obj["odata.count"], 10)
                    }
            };
        var EdmLiteral = DX.Class.inherit({
                ctor: function(value) {
                    this._value = value
                },
                valueOf: function() {
                    return this._value
                }
            });
        var serializeDate = function() {
                var pad = function(part) {
                        part = String(part);
                        if (part.length < 2)
                            part = "0" + part;
                        return part
                    };
                return function(date) {
                        var result = ["datetime'", date.getFullYear(), "-", pad(date.getMonth() + 1), "-", pad(date.getDate())];
                        if (date.getHours() || date.getMinutes() || date.getSeconds() || date.getMilliseconds()) {
                            result.push("T", pad(date.getHours()), ":", pad(date.getMinutes()), ":", pad(date.getSeconds()));
                            if (date.getMilliseconds())
                                result.push(".", date.getMilliseconds())
                        }
                        result.push("'");
                        return result.join("")
                    }
            }();
        var serializePropName = function(propName) {
                if (propName instanceof EdmLiteral)
                    return propName.valueOf();
                return propName.replace(/\./g, "/")
            };
        var serializeValueV4 = function(value) {
                if (value instanceof Date)
                    return utils.formatIso8601Date(value);
                return serializeValueV2(value)
            };
        var serializeValueV2 = function(value) {
                if (value instanceof Date)
                    return serializeDate(value);
                if (value instanceof Guid)
                    return "guid'" + value + "'";
                if (value instanceof EdmLiteral)
                    return value.valueOf();
                if (typeof value === "string")
                    return "'" + value.replace(/'/g, "''") + "'";
                return String(value)
            };
        var DEFAULT_PROTOCOL_VERSION = 2;
        var serializeValue = function(value, protocolVersion) {
                protocolVersion = protocolVersion || DEFAULT_PROTOCOL_VERSION;
                switch (protocolVersion) {
                    case 2:
                    case 3:
                        return serializeValueV2(value);
                    case 4:
                        return serializeValueV4(value);
                    default:
                        throw new Error("Unknown OData protocol version");
                }
            };
        var serializeKey = function(key, protocolVersion) {
                if ($.isPlainObject(key)) {
                    var parts = [];
                    $.each(key, function(k, v) {
                        parts.push(serializePropName(k) + "=" + serializeValue(v, protocolVersion))
                    });
                    return parts.join()
                }
                return serializeValue(key)
            };
        var traverse = function(obj, transformer) {
                $.each(obj, function(i, val) {
                    if (val !== null && typeof val === "object")
                        traverse(val, transformer);
                    else if (typeof val === "string")
                        transformer(obj, i)
                })
            };
        var keyConverters = {
                String: function(value) {
                    return value + ""
                },
                Int32: function(value) {
                    return Math.floor(value)
                },
                Int64: function(value) {
                    if (value instanceof EdmLiteral)
                        return value;
                    return new EdmLiteral(value + "L")
                },
                Guid: function(value) {
                    if (value instanceof Guid)
                        return value;
                    return new Guid(value)
                },
                Boolean: function(value) {
                    return !!value
                }
            };
        var compileCriteria = function() {
                var createBinaryOperationFormatter = function(op) {
                        return function(prop, val, bag) {
                                bag.push(prop, " ", op, " ", val)
                            }
                    };
                var createStringFuncFormatter = function(op, reverse) {
                        return function(prop, val, bag) {
                                if (reverse)
                                    bag.push(op, "(", val, ",", prop, ")");
                                else
                                    bag.push(op, "(", prop, ",", val, ")")
                            }
                    };
                var formatters = {
                        "=": createBinaryOperationFormatter("eq"),
                        "<>": createBinaryOperationFormatter("ne"),
                        ">": createBinaryOperationFormatter("gt"),
                        ">=": createBinaryOperationFormatter("ge"),
                        "<": createBinaryOperationFormatter("lt"),
                        "<=": createBinaryOperationFormatter("le"),
                        startswith: createStringFuncFormatter("startswith"),
                        endswith: createStringFuncFormatter("endswith"),
                        contains: createStringFuncFormatter("substringof", true),
                        notcontains: createStringFuncFormatter("not substringof", true)
                    };
                var compileBinary = function(criteria, bag, protocolVersion) {
                        criteria = data.utils.normalizeBinaryCriterion(criteria);
                        var op = criteria[1],
                            formatter = formatters[op.toLowerCase()];
                        if (!formatter)
                            throw Error("Unknown filter operation: " + op);
                        formatter(serializePropName(criteria[0]), serializeValue(criteria[2], protocolVersion), bag)
                    };
                var compileGroup = function(criteria, bag, protocolVersion) {
                        var pushAnd = false;
                        $.each(criteria, function() {
                            if ($.isArray(this)) {
                                if (pushAnd)
                                    bag.push(" and ");
                                bag.push("(");
                                compileCore(this, bag, protocolVersion);
                                bag.push(")");
                                pushAnd = true
                            }
                            else {
                                bag.push(/and|&/i.test(this) ? " and " : " or ");
                                pushAnd = false
                            }
                        })
                    };
                var compileCore = function(criteria, bag, protocolVersion) {
                        if ($.isArray(criteria[0]))
                            compileGroup(criteria, bag, protocolVersion);
                        else
                            compileBinary(criteria, bag, protocolVersion)
                    };
                return function(criteria, protocolVersion) {
                        var bag = [];
                        compileCore(criteria, bag, protocolVersion);
                        return bag.join("")
                    }
            }();
        var createODataQueryAdapter = function(queryOptions) {
                var sorting = [],
                    criteria = [],
                    select,
                    skip,
                    take,
                    countQuery;
                var hasSlice = function() {
                        return skip || take !== undefined
                    };
                var sortCore = function(getter, desc, reset) {
                        if (hasSlice() || typeof getter !== "string")
                            return false;
                        if (reset)
                            sorting = [];
                        var rule = serializePropName(getter);
                        if (desc)
                            rule += " desc";
                        sorting.push(rule)
                    };
                var generateExpand = function() {
                        var hash = {};
                        if (queryOptions.expand)
                            $.each($.makeArray(queryOptions.expand), function() {
                                hash[serializePropName(this)] = 1
                            });
                        if (select)
                            $.each(select, function() {
                                var path = this.split(".");
                                if (path.length < 2)
                                    return;
                                path.pop();
                                hash[serializePropName(path.join("."))] = 1
                            });
                        return $.map(hash, function(k, v) {
                                return v
                            }).join() || undefined
                    };
                var requestData = function() {
                        var result = {};
                        if (!countQuery) {
                            if (sorting.length)
                                result["$orderby"] = sorting.join(",");
                            if (skip)
                                result["$skip"] = skip;
                            if (take !== undefined)
                                result["$top"] = take;
                            if (select)
                                result["$select"] = serializePropName(select.join());
                            result["$expand"] = generateExpand()
                        }
                        if (criteria.length)
                            result["$filter"] = compileCriteria(criteria.length < 2 ? criteria[0] : criteria, queryOptions.version);
                        if (countQuery)
                            result["$top"] = 0;
                        if (queryOptions.requireTotalCount || countQuery)
                            if (queryOptions.version !== 4)
                                result["$inlinecount"] = "allpages";
                            else
                                result["$count"] = "true";
                        return result
                    };
                return {
                        exec: function(url) {
                            return sendRequest({
                                    url: url,
                                    params: $.extend(requestData(), queryOptions && queryOptions.params)
                                }, {
                                    beforeSend: queryOptions.beforeSend,
                                    jsonp: queryOptions.jsonp,
                                    withCredentials: queryOptions.withCredentials,
                                    countOnly: countQuery
                                })
                        },
                        sortBy: function(getter, desc) {
                            return sortCore(getter, desc, true)
                        },
                        thenBy: function(getter, desc) {
                            return sortCore(getter, desc, false)
                        },
                        slice: function(skipCount, takeCount) {
                            if (hasSlice())
                                return false;
                            skip = skipCount;
                            take = takeCount
                        },
                        filter: function(criterion) {
                            if (hasSlice() || $.isFunction(criterion))
                                return false;
                            if (!$.isArray(criterion))
                                criterion = $.makeArray(arguments);
                            if (criteria.length)
                                criteria.push("and");
                            criteria.push(criterion)
                        },
                        select: function(expr) {
                            if (select || $.isFunction(expr))
                                return false;
                            if (!$.isArray(expr))
                                expr = $.makeArray(arguments);
                            select = expr
                        },
                        count: function() {
                            countQuery = true
                        }
                    }
            };
        $.extend(true, data, {
            EdmLiteral: EdmLiteral,
            utils: {odata: {
                    sendRequest: sendRequest,
                    serializePropName: serializePropName,
                    serializeValue: serializeValue,
                    serializeKey: serializeKey,
                    keyConverters: keyConverters
                }},
            queryAdapters: {odata: createODataQueryAdapter}
        });
        data.OData__internals = {interpretJsonFormat: interpretJsonFormat}
    })(jQuery, DevExpress);
    /*! Module core, file data.store.abstract.js */
    (function($, DX, undefined) {
        var Class = DX.Class,
            abstract = DX.abstract,
            data = DX.data,
            normalizeSortingInfo = data.utils.normalizeSortingInfo;
        var STORE_CALLBACK_NAMES = ["loading", "loaded", "modifying", "modified", "inserting", "inserted", "updating", "updated", "removing", "removed"];
        function multiLevelGroup(query, groupInfo) {
            query = query.groupBy(groupInfo[0].selector);
            if (groupInfo.length > 1)
                query = query.select(function(g) {
                    return $.extend({}, g, {items: multiLevelGroup(data.query(g.items), groupInfo.slice(1)).toArray()})
                });
            return query
        }
        data.utils.multiLevelGroup = multiLevelGroup;
        function arrangeSortingInfo(groupInfo, sortInfo) {
            var filteredGroup = [];
            $.each(groupInfo, function(_, group) {
                var collision = $.grep(sortInfo, function(sort) {
                        return group.selector == sort.selector
                    });
                if (collision.length < 1)
                    filteredGroup.push(group)
            });
            return filteredGroup.concat(sortInfo)
        }
        data.Store = Class.inherit({
            ctor: function(options) {
                var that = this;
                options = options || {};
                $.each(STORE_CALLBACK_NAMES, function() {
                    var callbacks = that[this] = $.Callbacks();
                    if (this in options)
                        callbacks.add(options[this])
                });
                this._key = options.key;
                this._errorHandler = options.errorHandler;
                this._useDefaultSearch = true
            },
            _customLoadOptions: function() {
                return null
            },
            key: function() {
                return this._key
            },
            keyOf: function(obj) {
                if (!this._keyGetter)
                    this._keyGetter = data.utils.compileGetter(this.key());
                return this._keyGetter(obj)
            },
            _requireKey: function() {
                if (!this.key())
                    throw Error("Key expression is required for this operation");
            },
            load: function(options) {
                var that = this;
                options = options || {};
                this.loading.fire(options);
                return this._loadImpl(options).done(function(result, extra) {
                        that.loaded.fire(result, extra)
                    })
            },
            _loadImpl: function(options) {
                var filter = options.filter,
                    sort = options.sort,
                    select = options.select,
                    group = options.group,
                    skip = options.skip,
                    take = options.take,
                    q = this.createQuery(options);
                if (filter)
                    q = q.filter(filter);
                if (group)
                    group = normalizeSortingInfo(group);
                if (sort || group) {
                    sort = normalizeSortingInfo(sort || []);
                    if (group)
                        sort = arrangeSortingInfo(group, sort);
                    $.each(sort, function(index) {
                        q = q[index ? "thenBy" : "sortBy"](this.selector, this.desc)
                    })
                }
                if (select)
                    q = q.select(select);
                if (group)
                    q = multiLevelGroup(q, group);
                if (take || skip)
                    q = q.slice(skip || 0, take);
                return q.enumerate()
            },
            createQuery: abstract,
            totalCount: function(options) {
                return this._addFailHandlers(this._totalCountImpl(options))
            },
            _totalCountImpl: function(options) {
                options = options || {};
                var q = this.createQuery(),
                    group = options.group,
                    filter = options.filter;
                if (filter)
                    q = q.filter(filter);
                if (group) {
                    group = normalizeSortingInfo(group);
                    q = multiLevelGroup(q, group)
                }
                return q.count()
            },
            byKey: function(key, extraOptions) {
                return this._addFailHandlers(this._byKeyImpl(key, extraOptions))
            },
            _byKeyImpl: abstract,
            insert: function(values) {
                var that = this;
                that.modifying.fire();
                that.inserting.fire(values);
                return that._addFailHandlers(that._insertImpl(values).done(function(callbackValues, callbackKey) {
                        that.inserted.fire(callbackValues, callbackKey);
                        that.modified.fire()
                    }))
            },
            _insertImpl: abstract,
            update: function(key, values) {
                var that = this;
                that.modifying.fire();
                that.updating.fire(key, values);
                return that._addFailHandlers(that._updateImpl(key, values).done(function(callbackKey, callbackValues) {
                        that.updated.fire(callbackKey, callbackValues);
                        that.modified.fire()
                    }))
            },
            _updateImpl: abstract,
            remove: function(key) {
                var that = this;
                that.modifying.fire();
                that.removing.fire(key);
                return that._addFailHandlers(that._removeImpl(key).done(function(callbackKey) {
                        that.removed.fire(callbackKey);
                        that.modified.fire()
                    }))
            },
            _removeImpl: abstract,
            _addFailHandlers: function(deferred) {
                return deferred.fail(this._errorHandler, data._handleError)
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file data.store.array.js */
    (function($, DX, undefined) {
        var data = DX.data,
            Guid = data.Guid;
        var trivialPromise = function(_) {
                var d = $.Deferred();
                return d.resolve.apply(d, arguments).promise()
            };
        var rejectedPromise = function(_) {
                var d = $.Deferred();
                return d.reject.apply(d, arguments).promise()
            };
        data.ArrayStore = data.Store.inherit({
            ctor: function(options) {
                if ($.isArray(options))
                    options = {data: options};
                else
                    options = options || {};
                this.callBase(options);
                var initialArray = options.data;
                if (initialArray && !$.isArray(initialArray))
                    throw Error("Invalid 'data' option value");
                this._array = initialArray || []
            },
            createQuery: function() {
                return data.query(this._array, {errorHandler: this._errorHandler})
            },
            _byKeyImpl: function(key) {
                return trivialPromise(this._array[this._indexByKey(key)])
            },
            _insertImpl: function(values) {
                var keyExpr = this.key(),
                    keyValue,
                    obj = {};
                $.extend(obj, values);
                if (keyExpr) {
                    keyValue = this.keyOf(obj);
                    if (keyValue === undefined || typeof keyValue === "object" && $.isEmptyObject(keyValue)) {
                        if ($.isArray(keyExpr))
                            throw Error("Compound keys cannot be auto-generated");
                        keyValue = obj[keyExpr] = String(new Guid)
                    }
                    else if (this._array[this._indexByKey(keyValue)] !== undefined)
                        return rejectedPromise(Error("Attempt to insert an item with the duplicate key"))
                }
                else
                    keyValue = obj;
                this._array.push(obj);
                return trivialPromise(values, keyValue)
            },
            _updateImpl: function(key, values) {
                var target;
                if (this.key()) {
                    var index = this._indexByKey(key);
                    if (index < 0)
                        return rejectedPromise(Error("Data item not found"));
                    target = this._array[index]
                }
                else
                    target = key;
                DX.utils.deepExtendArraySafe(target, values);
                return trivialPromise(key, values)
            },
            _removeImpl: function(key) {
                var index = this._indexByKey(key);
                if (index > -1)
                    this._array.splice(index, 1);
                return trivialPromise(key)
            },
            _indexByKey: function(key) {
                for (var i = 0, arrayLength = this._array.length; i < arrayLength; i++)
                    if (data.utils.keysEqual(this.key(), this.keyOf(this._array[i]), key))
                        return i;
                return -1
            },
            clear: function() {
                this._array = []
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file data.store.local.js */
    (function($, DX, undefined) {
        var Class = DX.Class,
            abstract = DX.abstract,
            data = DX.data;
        var LocalStoreBackend = Class.inherit({
                ctor: function(store, storeOptions) {
                    this._store = store;
                    this._dirty = false;
                    var immediate = this._immediate = storeOptions.immediate;
                    var flushInterval = Math.max(100, storeOptions.flushInterval || 10 * 1000);
                    if (!immediate) {
                        var saveProxy = $.proxy(this.save, this);
                        setInterval(saveProxy, flushInterval);
                        $(window).on("beforeunload", saveProxy);
                        if (window.cordova)
                            document.addEventListener("pause", saveProxy, false)
                    }
                },
                notifyChanged: function() {
                    this._dirty = true;
                    if (this._immediate)
                        this.save()
                },
                load: function() {
                    this._store._array = this._loadImpl();
                    this._dirty = false
                },
                save: function() {
                    if (!this._dirty)
                        return;
                    this._saveImpl(this._store._array);
                    this._dirty = false
                },
                _loadImpl: abstract,
                _saveImpl: abstract
            });
        var DomLocalStoreBackend = LocalStoreBackend.inherit({
                ctor: function(store, storeOptions) {
                    this.callBase(store, storeOptions);
                    var name = storeOptions.name;
                    if (!name)
                        throw Error("Name is required");
                    this._key = "dx-data-localStore-" + name
                },
                _loadImpl: function() {
                    var raw = localStorage.getItem(this._key);
                    if (raw)
                        return JSON.parse(raw);
                    return []
                },
                _saveImpl: function(array) {
                    if (!array.length)
                        localStorage.removeItem(this._key);
                    else
                        localStorage.setItem(this._key, JSON.stringify(array))
                }
            });
        var localStoreBackends = {dom: DomLocalStoreBackend};
        data.LocalStore = data.ArrayStore.inherit({
            ctor: function(options) {
                if (typeof options === "string")
                    options = {name: options};
                else
                    options = options || {};
                this.callBase(options);
                this._backend = new localStoreBackends[options.backend || "dom"](this, options);
                this._backend.load()
            },
            clear: function() {
                this.callBase();
                this._backend.notifyChanged()
            },
            _insertImpl: function(values) {
                var b = this._backend;
                return this.callBase(values).done($.proxy(b.notifyChanged, b))
            },
            _updateImpl: function(key, values) {
                var b = this._backend;
                return this.callBase(key, values).done($.proxy(b.notifyChanged, b))
            },
            _removeImpl: function(key) {
                var b = this._backend;
                return this.callBase(key).done($.proxy(b.notifyChanged, b))
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file data.store.odata.js */
    (function($, DX, undefined) {
        var Class = DX.Class,
            data = DX.data,
            odataUtils = data.utils.odata;
        var escapeServiceOperationParams = function(params, version) {
                if (!params)
                    return params;
                var result = {};
                $.each(params, function(k, v) {
                    result[k] = odataUtils.serializeValue(v, version)
                });
                return result
            };
        var convertSimpleKey = function(keyType, keyValue) {
                var converter = odataUtils.keyConverters[keyType];
                if (!converter)
                    throw Error("Unknown key type: " + keyType);
                return converter(keyValue)
            };
        var SharedMethods = {
                _extractServiceOptions: function(options) {
                    options = options || {};
                    this._url = String(options.url).replace(/\/+$/, "");
                    this._beforeSend = options.beforeSend;
                    this._jsonp = options.jsonp;
                    this._version = options.version;
                    this._withCredentials = options.withCredentials
                },
                _sendRequest: function(url, method, params, payload) {
                    return odataUtils.sendRequest({
                            url: url,
                            method: method,
                            params: params || {},
                            payload: payload
                        }, {
                            beforeSend: this._beforeSend,
                            jsonp: this._jsonp,
                            withCredentials: this._withCredentials
                        })
                },
                version: function() {
                    return this._version
                }
            };
        var ODataStore = data.Store.inherit({
                ctor: function(options) {
                    this.callBase(options);
                    this._extractServiceOptions(options);
                    this._keyType = options.keyType
                },
                _customLoadOptions: function() {
                    return ["expand", "customQueryParams"]
                },
                _byKeyImpl: function(key, extraOptions) {
                    var params = {};
                    if (extraOptions)
                        if (extraOptions.expand)
                            params["$expand"] = $.map($.makeArray(extraOptions.expand), odataUtils.serializePropName).join();
                    return this._sendRequest(this._byKeyUrl(key), "GET", params)
                },
                createQuery: function(loadOptions) {
                    loadOptions = loadOptions || {};
                    return data.query(this._url, {
                            beforeSend: this._beforeSend,
                            errorHandler: this._errorHandler,
                            jsonp: this._jsonp,
                            version: this._version,
                            withCredentials: this._withCredentials,
                            params: escapeServiceOperationParams(loadOptions.customQueryParams, this._version),
                            expand: loadOptions.expand,
                            requireTotalCount: loadOptions.requireTotalCount
                        })
                },
                _insertImpl: function(values) {
                    this._requireKey();
                    var that = this,
                        d = $.Deferred();
                    $.when(this._sendRequest(this._url, "POST", null, values)).done(function(serverResponse) {
                        d.resolve(values, that.keyOf(serverResponse))
                    }).fail($.proxy(d.reject, d));
                    return d.promise()
                },
                _updateImpl: function(key, values) {
                    var d = $.Deferred();
                    $.when(this._sendRequest(this._byKeyUrl(key), "MERGE", null, values)).done(function() {
                        d.resolve(key, values)
                    }).fail($.proxy(d.reject, d));
                    return d.promise()
                },
                _removeImpl: function(key) {
                    var d = $.Deferred();
                    $.when(this._sendRequest(this._byKeyUrl(key), "DELETE")).done(function() {
                        d.resolve(key)
                    }).fail($.proxy(d.reject, d));
                    return d.promise()
                },
                _byKeyUrl: function(key) {
                    var keyType = this._keyType;
                    if ($.isPlainObject(keyType))
                        $.each(keyType, function(subKeyName, subKeyType) {
                            key[subKeyName] = convertSimpleKey(subKeyType, key[subKeyName])
                        });
                    else if (keyType)
                        key = convertSimpleKey(keyType, key);
                    return this._url + "(" + encodeURIComponent(odataUtils.serializeKey(key, this._version)) + ")"
                }
            }).include(SharedMethods);
        var ODataContext = Class.inherit({
                ctor: function(options) {
                    var that = this;
                    that._extractServiceOptions(options);
                    that._errorHandler = options.errorHandler;
                    $.each(options.entities || [], function(entityAlias, entityOptions) {
                        that[entityAlias] = new ODataStore($.extend({}, options, {url: that._url + "/" + encodeURIComponent(entityOptions.name || entityAlias)}, entityOptions))
                    })
                },
                get: function(operationName, params) {
                    return this.invoke(operationName, params, "GET")
                },
                invoke: function(operationName, params, httpMethod) {
                    httpMethod = httpMethod || "POST";
                    var d = $.Deferred();
                    $.when(this._sendRequest(this._url + "/" + encodeURIComponent(operationName), httpMethod, escapeServiceOperationParams(params, this._version))).done(function(r) {
                        if (r && operationName in r)
                            r = r[operationName];
                        d.resolve(r)
                    }).fail([this._errorHandler, data._handleError, $.proxy(d.reject, d)]);
                    return d.promise()
                },
                objectLink: function(entityAlias, key) {
                    var store = this[entityAlias];
                    if (!store)
                        throw Error("Unknown entity name or alias: " + entityAlias);
                    return {__metadata: {uri: store._byKeyUrl(key)}}
                }
            }).include(SharedMethods);
        $.extend(data, {
            ODataStore: ODataStore,
            ODataContext: ODataContext
        })
    })(jQuery, DevExpress);
    /*! Module core, file data.store.rest.js */
    (function($, DX, undefined) {
        var data = DX.data;
        function createAjaxFailureHandler(deferred) {
            return function(xhr, textStatus) {
                    if (!xhr || !xhr.getResponseHeader)
                        deferred.reject.apply(deferred, arguments);
                    else
                        deferred.reject(Error(data.utils.errorMessageFromXhr(xhr, textStatus)))
                }
        }
        function operationCustomizerPropName(operationName) {
            return "_customize" + DX.inflector.camelize(operationName, true)
        }
        function pathPropName(operationName) {
            return "_" + operationName + "Path"
        }
        data.RestStore = data.Store.inherit({
            ctor: function(options) {
                DX.utils.logger.warn("RestStore is deprecated, use CustomStore instead");
                var that = this;
                that.callBase(options);
                options = options || {};
                that._url = String(options.url).replace(/\/+$/, "");
                that._jsonp = options.jsonp;
                that._withCredentials = options.withCredentials;
                $.each(["Load", "Insert", "Update", "Remove", "ByKey", "Operation"], function() {
                    var value = options["customize" + this];
                    if (value)
                        that[operationCustomizerPropName(this)] = value
                });
                $.each(["load", "insert", "update", "remove", "byKey"], function() {
                    var value = options[this + "Path"];
                    if (value)
                        that[pathPropName(this)] = value
                })
            },
            _loadImpl: function(options) {
                var d = $.Deferred(),
                    ajaxOptions = {
                        url: this._formatUrlNoKey("load"),
                        type: "GET"
                    };
                $.when(this._createAjax(ajaxOptions, "load", options)).done($.proxy(d.resolve, d)).fail(createAjaxFailureHandler(d));
                return this._addFailHandlers(d.promise())
            },
            createQuery: function() {
                throw Error("Not supported");
            },
            _insertImpl: function(values) {
                var d = $.Deferred(),
                    that = this,
                    ajaxOptions = {
                        url: this._formatUrlNoKey("insert"),
                        type: "POST",
                        contentType: "application/json",
                        data: JSON.stringify(values)
                    };
                $.when(this._createAjax(ajaxOptions, "insert")).done(function(serverResponse) {
                    d.resolve(values, that.key() && that.keyOf(serverResponse))
                }).fail(createAjaxFailureHandler(d));
                return d.promise()
            },
            _updateImpl: function(key, values) {
                var d = $.Deferred(),
                    ajaxOptions = {
                        url: this._formatUrlWithKey("update", key),
                        type: "PUT",
                        contentType: "application/json",
                        data: JSON.stringify(values)
                    };
                $.when(this._createAjax(ajaxOptions, "update")).done(function() {
                    d.resolve(key, values)
                }).fail(createAjaxFailureHandler(d));
                return d.promise()
            },
            _removeImpl: function(key) {
                var d = $.Deferred(),
                    ajaxOptions = {
                        url: this._formatUrlWithKey("remove", key),
                        type: "DELETE"
                    };
                $.when(this._createAjax(ajaxOptions, "remove")).done(function() {
                    d.resolve(key)
                }).fail(createAjaxFailureHandler(d));
                return d.promise()
            },
            _byKeyImpl: function(key) {
                var d = $.Deferred(),
                    ajaxOptions = {
                        url: this._formatUrlWithKey("byKey", key),
                        type: "GET"
                    };
                $.when(this._createAjax(ajaxOptions, "byKey")).done(function(data) {
                    d.resolve(data)
                }).fail(createAjaxFailureHandler(d));
                return d.promise()
            },
            _createAjax: function(ajaxOptions, operationName, extra) {
                var customizationFunc,
                    customizationResult;
                function isDeferred(obj) {
                    return "done" in obj && "fail" in obj
                }
                if (this._jsonp && ajaxOptions.type === "GET")
                    ajaxOptions.dataType = "jsonp";
                else
                    $.extend(true, ajaxOptions, {xhrFields: {withCredentials: this._withCredentials}});
                customizationFunc = this[operationCustomizerPropName("operation")];
                if (customizationFunc) {
                    customizationResult = customizationFunc(ajaxOptions, operationName, extra);
                    if (customizationResult) {
                        if (isDeferred(customizationResult))
                            return customizationResult;
                        ajaxOptions = customizationResult
                    }
                }
                customizationFunc = this[operationCustomizerPropName(operationName)];
                if (customizationFunc) {
                    customizationResult = customizationFunc(ajaxOptions, extra);
                    if (customizationResult) {
                        if (isDeferred(customizationResult))
                            return customizationResult;
                        ajaxOptions = customizationResult
                    }
                }
                return $.ajax(ajaxOptions)
            },
            _formatUrlNoKey: function(operationName) {
                var url = this._url,
                    path = this[pathPropName(operationName)];
                if (!path)
                    return url;
                if ($.isFunction(path))
                    return path(url);
                return url + "/" + path
            },
            _formatUrlWithKey: function(operationName, key) {
                var url = this._url,
                    path = this[pathPropName(operationName)];
                if (!path)
                    return url + "/" + encodeURIComponent(key);
                if ($.isFunction(path))
                    return path(url, key);
                return url + "/" + path + "/" + encodeURIComponent(key)
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file data.store.custom.js */
    (function($, DX, undefined) {
        var data = DX.data;
        var ERROR_QUERY_NOT_SUPPORTED = "CustomStore does not support creating queries",
            ERROR_MISSING_USER_FUNC = "Required option is not specified or is not a function: ",
            ERROR_INVALID_RETURN = "Invalid return value: ";
        var TOTAL_COUNT = "totalCount",
            LOAD = "load",
            BY_KEY = "byKey",
            INSERT = "insert",
            UPDATE = "update",
            REMOVE = "remove";
        function isPromise(obj) {
            return obj && $.isFunction(obj.done) && $.isFunction(obj.fail) && $.isFunction(obj.promise)
        }
        function trivialPromise(value) {
            return $.Deferred().resolve(value).promise()
        }
        function ensureRequiredFuncOption(name, obj) {
            if (!$.isFunction(obj))
                throw Error(ERROR_MISSING_USER_FUNC + name);
        }
        function throwInvalidUserFuncResult(name) {
            throw Error(ERROR_INVALID_RETURN + name);
        }
        function createUserFuncFailureHandler(pendingDeferred) {
            function errorMessageFromXhr(promiseArguments) {
                var xhr = promiseArguments[0],
                    textStatus = promiseArguments[1];
                if (!xhr || !xhr.getResponseHeader)
                    return null;
                return data.utils.errorMessageFromXhr(xhr, textStatus)
            }
            return function(arg) {
                    var error;
                    if (arg instanceof Error)
                        error = arg;
                    else
                        error = Error(errorMessageFromXhr(arguments) || arg && String(arg) || "Unknown error");
                    pendingDeferred.reject(error)
                }
        }
        data.CustomStore = data.Store.inherit({
            ctor: function(options) {
                options = options || {};
                this.callBase(options);
                this._useDefaultSearch = false;
                this._loadFunc = options[LOAD];
                this._totalCountFunc = options[TOTAL_COUNT];
                this._byKeyFunc = options[BY_KEY] || options.lookup;
                this._insertFunc = options[INSERT];
                this._updateFunc = options[UPDATE];
                this._removeFunc = options[REMOVE]
            },
            createQuery: function() {
                throw Error(ERROR_QUERY_NOT_SUPPORTED);
            },
            _totalCountImpl: function(options) {
                var userFunc = this._totalCountFunc,
                    userResult,
                    d = $.Deferred();
                ensureRequiredFuncOption(TOTAL_COUNT, userFunc);
                userResult = userFunc(options);
                if (!isPromise(userResult)) {
                    userResult = Number(userResult);
                    if (!isFinite(userResult))
                        throwInvalidUserFuncResult(TOTAL_COUNT);
                    userResult = trivialPromise(userResult)
                }
                userResult.done(function(count) {
                    d.resolve(Number(count))
                }).fail(createUserFuncFailureHandler(d));
                return d.promise()
            },
            _loadImpl: function(options) {
                var userFunc = this._loadFunc,
                    userResult,
                    d = $.Deferred();
                ensureRequiredFuncOption(LOAD, userFunc);
                userResult = userFunc(options);
                if ($.isArray(userResult))
                    userResult = trivialPromise(userResult);
                else if (userResult === null || userResult === undefined)
                    userResult = trivialPromise([]);
                else if (!isPromise(userResult))
                    throwInvalidUserFuncResult(LOAD);
                userResult.done(function(data, extra) {
                    d.resolve(data, extra)
                }).fail(createUserFuncFailureHandler(d));
                return this._addFailHandlers(d.promise())
            },
            _byKeyImpl: function(key) {
                var userFunc = this._byKeyFunc,
                    userResult,
                    d = $.Deferred();
                ensureRequiredFuncOption(BY_KEY, userFunc);
                userResult = userFunc(key);
                if (!isPromise(userResult))
                    userResult = trivialPromise(userResult);
                userResult.done(function(obj) {
                    d.resolve(obj)
                }).fail(createUserFuncFailureHandler(d));
                return d.promise()
            },
            _insertImpl: function(values) {
                var userFunc = this._insertFunc,
                    userResult,
                    d = $.Deferred();
                ensureRequiredFuncOption(INSERT, userFunc);
                userResult = userFunc(values);
                if (!isPromise(userResult))
                    userResult = trivialPromise(userResult);
                userResult.done(function(newKey) {
                    d.resolve(values, newKey)
                }).fail(createUserFuncFailureHandler(d));
                return d.promise()
            },
            _updateImpl: function(key, values) {
                var userFunc = this._updateFunc,
                    userResult,
                    d = $.Deferred();
                ensureRequiredFuncOption(UPDATE, userFunc);
                userResult = userFunc(key, values);
                if (!isPromise(userResult))
                    userResult = trivialPromise();
                userResult.done(function() {
                    d.resolve(key, values)
                }).fail(createUserFuncFailureHandler(d));
                return d.promise()
            },
            _removeImpl: function(key) {
                var userFunc = this._removeFunc,
                    userResult,
                    d = $.Deferred();
                ensureRequiredFuncOption(REMOVE, userFunc);
                userResult = userFunc(key);
                if (!isPromise(userResult))
                    userResult = trivialPromise();
                userResult.done(function() {
                    d.resolve(key)
                }).fail(createUserFuncFailureHandler(d));
                return d.promise()
            }
        });
        data.CustomStore_internals = {ERRORS: {
                QUERY_NOT_SUPPORTED: ERROR_QUERY_NOT_SUPPORTED,
                MISSING_USER_FUNC: ERROR_MISSING_USER_FUNC,
                INVALID_RETURN: ERROR_INVALID_RETURN
            }}
    })(jQuery, DevExpress);
    /*! Module core, file data.dataSource.js */
    (function($, DX, undefined) {
        var data = DX.data,
            CustomStore = data.CustomStore,
            Class = DX.Class;
        var storeTypeRegistry = {
                jaydata: "JayDataStore",
                breeze: "BreezeStore",
                odata: "ODataStore",
                local: "LocalStore",
                array: "ArrayStore"
            };
        function normalizeDataSourceOptions(options) {
            var store;
            function createCustomStoreFromLoadFunc() {
                var storeConfig = {};
                $.each(["key", "load", "byKey", "lookup", "totalCount", "insert", "update", "remove"], function() {
                    storeConfig[this] = options[this];
                    delete options[this]
                });
                return new CustomStore(storeConfig)
            }
            function createStoreFromConfig(storeConfig) {
                var storeCtor = data[storeTypeRegistry[storeConfig.type]];
                delete storeConfig.type;
                return new storeCtor(storeConfig)
            }
            function createCustomStoreFromUrl(url) {
                return new CustomStore({load: function() {
                            return $.getJSON(url)
                        }})
            }
            if (typeof options === "string")
                options = createCustomStoreFromUrl(options);
            if (options === undefined)
                options = [];
            if ($.isArray(options) || options instanceof data.Store)
                options = {store: options};
            else
                options = $.extend({}, options);
            store = options.store;
            if ("load" in options)
                store = createCustomStoreFromLoadFunc();
            else if ($.isArray(store))
                store = new data.ArrayStore(store);
            else if ($.isPlainObject(store))
                store = createStoreFromConfig($.extend({}, store));
            options.store = store;
            return options
        }
        function normalizeStoreLoadOptionAccessorArguments(originalArguments) {
            switch (originalArguments.length) {
                case 0:
                    return undefined;
                case 1:
                    return originalArguments[0]
            }
            return $.makeArray(originalArguments)
        }
        function generateStoreLoadOptionAccessor(optionName) {
            return function() {
                    var args = normalizeStoreLoadOptionAccessorArguments(arguments);
                    if (args !== undefined)
                        this._storeLoadOptions[optionName] = args;
                    return this._storeLoadOptions[optionName]
                }
        }
        function addOldUserDataSourceBackwardCompatibilityOptions(dataSource, storeLoadOptions) {
            storeLoadOptions.refresh = !dataSource._paginate || dataSource._pageIndex === 0;
            if (storeLoadOptions.searchValue !== null)
                storeLoadOptions.searchString = storeLoadOptions.searchValue
        }
        var DataSource = Class.inherit({
                ctor: function(options) {
                    options = normalizeDataSourceOptions(options);
                    this._store = options.store;
                    this._storeLoadOptions = this._extractLoadOptions(options);
                    this._mapFunc = options.map;
                    this._postProcessFunc = options.postProcess;
                    this._pageIndex = 0;
                    this._pageSize = options.pageSize !== undefined ? options.pageSize : 20;
                    this._items = [];
                    this._totalCount = -1;
                    this._isLoaded = false;
                    this._loadingCount = 0;
                    this._preferSync = options._preferSync;
                    this._loadQueue = this._createLoadQueue();
                    this._searchValue = "searchValue" in options ? options.searchValue : null;
                    this._searchOperation = options.searchOperation || "contains";
                    this._searchExpr = options.searchExpr;
                    this._paginate = options.paginate;
                    if (this._paginate === undefined)
                        this._paginate = !this.group();
                    this._isLastPage = !this._paginate;
                    this._userData = {};
                    this.changed = $.Callbacks();
                    this.loadError = $.Callbacks();
                    this.loadingChanged = $.Callbacks()
                },
                dispose: function() {
                    this.changed.empty();
                    this.loadError.empty();
                    this.loadingChanged.empty();
                    delete this._store;
                    this._disposed = true
                },
                _extractLoadOptions: function(options) {
                    var result = {},
                        names = ["sort", "filter", "select", "group", "requireTotalCount"],
                        customNames = this._store._customLoadOptions();
                    if (customNames)
                        names = names.concat(customNames);
                    $.each(names, function() {
                        result[this] = options[this]
                    });
                    return result
                },
                loadOptions: function() {
                    return this._storeLoadOptions
                },
                items: function() {
                    return this._items
                },
                pageIndex: function(newIndex) {
                    if (newIndex !== undefined) {
                        this._pageIndex = newIndex;
                        this._isLastPage = !this._paginate
                    }
                    return this._pageIndex
                },
                paginate: function(value) {
                    if (arguments.length < 1)
                        return this._paginate;
                    value = !!value;
                    if (this._paginate !== value) {
                        this._paginate = value;
                        this.pageIndex(0)
                    }
                },
                isLastPage: function() {
                    return this._isLastPage
                },
                sort: generateStoreLoadOptionAccessor("sort"),
                filter: function() {
                    var newFilter = normalizeStoreLoadOptionAccessorArguments(arguments);
                    if (newFilter !== undefined) {
                        this._storeLoadOptions.filter = newFilter;
                        this.pageIndex(0)
                    }
                    return this._storeLoadOptions.filter
                },
                group: generateStoreLoadOptionAccessor("group"),
                select: generateStoreLoadOptionAccessor("select"),
                searchValue: function(value) {
                    if (value !== undefined) {
                        this.pageIndex(0);
                        this._searchValue = value
                    }
                    return this._searchValue
                },
                searchOperation: function(op) {
                    if (op !== undefined) {
                        this.pageIndex(0);
                        this._searchOperation = op
                    }
                    return this._searchOperation
                },
                searchExpr: function(expr) {
                    var argc = arguments.length;
                    if (argc) {
                        if (argc > 1)
                            expr = $.makeArray(arguments);
                        this.pageIndex(0);
                        this._searchExpr = expr
                    }
                    return this._searchExpr
                },
                store: function() {
                    return this._store
                },
                key: function() {
                    return this._store && this._store.key()
                },
                totalCount: function() {
                    return this._totalCount
                },
                isLoaded: function() {
                    return this._isLoaded
                },
                isLoading: function() {
                    return this._loadingCount > 0
                },
                _createLoadQueue: function() {
                    return DX.createQueue()
                },
                _changeLoadingCount: function(increment) {
                    var oldLoading = this.isLoading(),
                        newLoading;
                    this._loadingCount += increment;
                    newLoading = this.isLoading();
                    if (oldLoading ^ newLoading)
                        this.loadingChanged.fire(newLoading)
                },
                _scheduleLoadCallbacks: function(deferred) {
                    var thisSource = this;
                    thisSource._changeLoadingCount(1);
                    deferred.always(function() {
                        thisSource._changeLoadingCount(-1)
                    })
                },
                _scheduleChangedCallbacks: function(deferred) {
                    var that = this;
                    deferred.done(function() {
                        that.changed.fire()
                    })
                },
                load: function() {
                    var thisSource = this,
                        d = $.Deferred(),
                        errorCallback = this.loadError,
                        storeLoadOptions;
                    this._scheduleLoadCallbacks(d);
                    this._scheduleChangedCallbacks(d);
                    storeLoadOptions = this._createStoreLoadOptions();
                    function loadTask() {
                        if (thisSource._disposed)
                            return undefined;
                        return thisSource._loadFromStore(storeLoadOptions, d)
                    }
                    this._loadQueue.add(function() {
                        loadTask();
                        return d.promise()
                    }, function() {
                        thisSource._changeLoadingCount(-1)
                    });
                    return d.promise().fail($.proxy(errorCallback.fire, errorCallback))
                },
                clone: function(patcher) {
                    var options = $.extend(true, {
                            store: this._store,
                            map: this._mapFunc,
                            postProcess: this._postProcessFunc,
                            paginate: this._paginate,
                            pageSize: this._pageSize,
                            searchExpr: this._searchExpr,
                            searchValue: this._searchValue,
                            searchOperation: this._searchOperation
                        }, this._storeLoadOptions);
                    if (patcher)
                        options = patcher(options);
                    return new DataSource(options)
                },
                _addSearchOptions: function(storeLoadOptions) {
                    if (this._disposed)
                        return;
                    if (this.store()._useDefaultSearch)
                        this._addSearchFilter(storeLoadOptions);
                    else {
                        storeLoadOptions.searchValue = this._searchValue;
                        storeLoadOptions.searchExpr = this._searchExpr
                    }
                },
                _createStoreLoadOptions: function() {
                    var result = $.extend({}, this._storeLoadOptions);
                    this._addSearchOptions(result);
                    if (this._paginate) {
                        result.pageIndex = this._pageIndex;
                        if (this._pageSize) {
                            result.skip = this._pageIndex * this._pageSize;
                            result.take = this._pageSize
                        }
                    }
                    result.userData = this._userData;
                    addOldUserDataSourceBackwardCompatibilityOptions(this, result);
                    return result
                },
                _addSearchFilter: function(storeLoadOptions) {
                    var value = this._searchValue,
                        op = this._searchOperation,
                        selector = this._searchExpr,
                        searchFilter = [];
                    if (!value)
                        return;
                    if (!selector)
                        selector = "this";
                    if (!$.isArray(selector))
                        selector = [selector];
                    $.each(selector, function(i, item) {
                        if (searchFilter.length)
                            searchFilter.push("or");
                        searchFilter.push([item, op, value])
                    });
                    if (storeLoadOptions.filter)
                        storeLoadOptions.filter = [searchFilter, storeLoadOptions.filter];
                    else
                        storeLoadOptions.filter = searchFilter
                },
                _loadFromStore: function(storeLoadOptions, pendingDeferred) {
                    var thisSource = this;
                    function handleSuccess(data, extra) {
                        function processResult() {
                            thisSource._processStoreLoadResult(data, extra, storeLoadOptions, pendingDeferred)
                        }
                        if (thisSource._preferSync)
                            processResult();
                        else
                            DX.utils.executeAsync(processResult)
                    }
                    return this.store().load(storeLoadOptions).done(handleSuccess).fail($.proxy(pendingDeferred.reject, pendingDeferred))
                },
                _processStoreLoadResult: function(data, extra, storeLoadOptions, pendingDeferred) {
                    var thisSource = this;
                    function resolvePendingDeferred() {
                        thisSource._isLoaded = true;
                        thisSource._totalCount = isFinite(extra.totalCount) ? extra.totalCount : -1;
                        return pendingDeferred.resolve(data, extra)
                    }
                    function proceedLoadingTotalCount() {
                        thisSource.store().totalCount(storeLoadOptions).done(function(count) {
                            extra.totalCount = count;
                            resolvePendingDeferred()
                        }).fail(function(){})
                    }
                    if (thisSource._disposed)
                        return;
                    data = thisSource._transformLoadedData(data);
                    if (!$.isPlainObject(extra))
                        extra = {};
                    thisSource._items = data;
                    if (!data.length || !thisSource._paginate || thisSource._pageSize && data.length < thisSource._pageSize)
                        thisSource._isLastPage = true;
                    if (storeLoadOptions.requireTotalCount && !isFinite(extra.totalCount))
                        proceedLoadingTotalCount();
                    else
                        resolvePendingDeferred()
                },
                _transformLoadedData: function(data) {
                    var result = $.makeArray(data);
                    if (this._mapFunc)
                        result = $.map(result, this._mapFunc);
                    if (this._postProcessFunc)
                        result = this._postProcessFunc(result);
                    return result
                }
            });
        data.Store.redefine({toDataSource: function(options) {
                DX.utils.logger.warn("toDataSource() method is deprecated, use 'new DevExpress.data.DataSource(...)' instead");
                return new DataSource($.extend({store: this}, options))
            }});
        $.extend(true, data, {
            DataSource: DataSource,
            createDataSource: function(options) {
                DX.utils.logger.warn("createDataSource() method is deprecated, use 'new DevExpress.data.DataSource(...)' instead");
                return new DataSource(options)
            },
            utils: {
                storeTypeRegistry: storeTypeRegistry,
                normalizeDataSourceOptions: normalizeDataSourceOptions
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file ko.js */
    (function($, DX, undefined) {
        if (!DX.support.hasKo)
            return;
        var ko = window.ko;
        (function checkKnockoutVersion(version) {
            version = version.split(".");
            if (version[0] < 2 || version[0] == 2 && version[1] < 3)
                throw Error("Your version of KnockoutJS is too old. Please upgrade KnockoutJS to 2.3.0 or later.");
        })(ko.version)
    })(jQuery, DevExpress);
    /*! Module core, file ng.js */
    (function($, DX, undefined) {
        if (!DX.support.hasNg)
            return;
        DX.ng = {module: window.angular.module("dx", ["ngSanitize"])}
    })(jQuery, DevExpress);
    /*! Module core, file component.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            dataUtils = DX.data.utils;
        var Component = DX.Class.inherit({
                NAME: "Component",
                _deprecatedOptions: {},
                _optionAliases: {},
                _setDefaultOptions: function(){},
                _defaultOptionsRules: function() {
                    return []
                },
                _setOptionsByDevice: function() {
                    var rules = this._defaultOptionsRules(),
                        currentDevice = DX.devices.current(),
                        result = {};
                    if (this._customRules)
                        rules = rules.concat(this._customRules);
                    var deviceMatch = function(device, filter) {
                            filter = $.makeArray(filter);
                            return filter.length === 1 && $.isEmptyObject(filter[0]) || utils.findBestMatches(device, filter).length > 0
                        };
                    $.each(rules, function(index, rule) {
                        var deviceFilter = rule.device || {},
                            match;
                        if ($.isFunction(deviceFilter))
                            match = deviceFilter(currentDevice);
                        else
                            match = deviceMatch(currentDevice, deviceFilter);
                        if (match)
                            $.extend(result, rule.options)
                    });
                    this.option(result)
                },
                _optionsByReference: function() {
                    return {}
                },
                ctor: function(options) {
                    if (!this.NAME)
                        throw Error("NAME is not specified");
                    this._options = {};
                    this._updateLockCount = 0;
                    this.optionChanged = $.Callbacks();
                    this.beginUpdate();
                    try {
                        this._suppressDeprecatedWarnings();
                        this._setDefaultOptions();
                        this._setOptionsByDevice();
                        this._resumeDeprecatedWarnings();
                        this._initialOptions = $.extend({}, this.option());
                        this._initOptions(options || {})
                    }
                    finally {
                        this.endUpdate()
                    }
                },
                _initOptions: function(options) {
                    this.option(options)
                },
                _optionValuesEqual: function(name, oldValue, newValue) {
                    oldValue = dataUtils.toComparable(oldValue, true);
                    newValue = dataUtils.toComparable(newValue, true);
                    if (oldValue && newValue && oldValue.jquery && newValue.jquery)
                        return newValue.is(oldValue);
                    if (oldValue === null || typeof oldValue !== "object")
                        return oldValue === newValue;
                    return false
                },
                _init: $.noop,
                _optionChanged: $.noop,
                instance: function() {
                    return this
                },
                beginUpdate: function() {
                    this._updateLockCount++
                },
                endUpdate: function() {
                    this._updateLockCount--;
                    if (!this._updateLockCount)
                        if (!this._initializing && !this._initialized) {
                            this._initializing = true;
                            try {
                                this._init()
                            }
                            finally {
                                this._initializing = false;
                                this._initialized = true
                            }
                        }
                },
                _logWarningIfDeprecated: function(option) {
                    var info = this._deprecatedOptions[option];
                    if (info && !this._deprecatedOptionsSuppressed)
                        this._logDeprecatedWarning(option, info)
                },
                _logDeprecatedWarningCount: 0,
                _logDeprecatedWarning: function(option, info) {
                    utils.logger.warn("'" + option + "' option is deprecated since " + info.since + ". " + info.message);
                    ++this._logDeprecatedWarningCount
                },
                _suppressDeprecatedWarnings: function() {
                    this._deprecatedOptionsSuppressed = true
                },
                _resumeDeprecatedWarnings: function() {
                    this._deprecatedOptionsSuppressed = false
                },
                _getOptionAliases: function(option) {
                    return $.map(this._optionAliases, function(aliasedOption, alias) {
                            return option === aliasedOption ? alias : undefined
                        })
                },
                _notifyOptionChanged: function(option, value, previousValue) {
                    var that = this,
                        optionWithAliases;
                    if (this._initialized) {
                        optionWithAliases = this._getOptionAliases(option);
                        optionWithAliases.push(option);
                        $.each(optionWithAliases, function(index, name) {
                            var topLevelName = name.split(/[.\[]/)[0];
                            that.optionChanged.fireWith(that, [topLevelName, value, previousValue]);
                            that._optionChanged(topLevelName, value, previousValue)
                        })
                    }
                },
                initialOption: function(optionName) {
                    var options = this._initialOptions;
                    return options[optionName]
                },
                option: function(options) {
                    var that = this,
                        name = options,
                        value = arguments[1];
                    if (arguments.length < 2 && $.type(name) !== "object") {
                        if (name) {
                            this._logWarningIfDeprecated(name);
                            if (this._optionAliases[name])
                                name = this._optionAliases[name]
                        }
                        $.each(this._optionAliases, function(alias, option) {
                            that._options[alias] = dataUtils.compileGetter(option)(that._options, {functionsAsIs: true})
                        });
                        return dataUtils.compileGetter(name)(that._options, {functionsAsIs: true})
                    }
                    if (typeof name === "string") {
                        options = {};
                        options[name] = value
                    }
                    that.beginUpdate();
                    try {
                        $.each(options, function(name, value) {
                            that._logWarningIfDeprecated(name);
                            if (that._optionAliases[name])
                                name = that._optionAliases[name];
                            var prevValue = dataUtils.compileGetter(name)(that._options, {functionsAsIs: true});
                            if (that._optionValuesEqual(name, prevValue, value))
                                return;
                            dataUtils.compileSetter(name)(that._options, value, {
                                functionsAsIs: true,
                                merge: !that._optionsByReference()[name]
                            });
                            that._notifyOptionChanged(name, value, prevValue)
                        })
                    }
                    finally {
                        that.endUpdate()
                    }
                }
            });
        $.extend(DX, {Component: Component})
    })(jQuery, DevExpress);
    /*! Module core, file DOMComponent.js */
    (function($, DX, undefined) {
        var windowResizeCallbacks = DX.utils.windowResizeCallbacks;
        var RTL_DIRECTION_CLASS = "dx-rtl",
            COMPONENT_NAMES_DATA_KEY = "dxComponents",
            VISIBILITY_CHANGE_CLASS = "dx-visibility-change-handler",
            VISIBILITY_CHANGE_EVENTNAMESPACE = "dxVisibilityChange";
        var DOMComponent = DX.Component.inherit({
                NAME: "DOMComponent",
                NAMESPACE: DX,
                _setDefaultOptions: function() {
                    this.callBase();
                    this.option({rtlEnabled: DX.rtlEnabled})
                },
                ctor: function(element, options) {
                    this._$element = $(element);
                    this._element().data(this.NAME, this);
                    this._attachInstanceToElement(this._$element);
                    this.disposing = $.Callbacks();
                    this.callBase(options)
                },
                _attachInstanceToElement: $.noop,
                _visibilityChanged: DX.abstract,
                _dimensionChanged: DX.abstract,
                _init: function() {
                    this.callBase();
                    this._attachWindowResizeCallback()
                },
                _attachWindowResizeCallback: function() {
                    if (this._isDimensionChangeSupported()) {
                        var windowResizeCallBack = this._windowResizeCallBack = $.proxy(this._dimensionChanged, this);
                        windowResizeCallbacks.add(windowResizeCallBack)
                    }
                },
                _isDimensionChangeSupported: function() {
                    return this._dimensionChanged !== DX.abstract
                },
                _render: function() {
                    this._toggleRTLDirection(this.option("rtlEnabled"));
                    this._renderVisiblityChange()
                },
                _renderVisiblityChange: function() {
                    if (!this._isVisibilityChangeSupported())
                        return;
                    this._element().addClass(VISIBILITY_CHANGE_CLASS);
                    this._attachVisiblityChangeHandlers()
                },
                _attachVisiblityChangeHandlers: function() {
                    var that = this;
                    that._element().off("." + VISIBILITY_CHANGE_EVENTNAMESPACE).on("dxhiding." + VISIBILITY_CHANGE_EVENTNAMESPACE, function() {
                        that._visibilityChanged(false)
                    }).on("dxshown." + VISIBILITY_CHANGE_EVENTNAMESPACE, function() {
                        that._visibilityChanged(true)
                    })
                },
                _isVisibilityChangeSupported: function() {
                    return this._visibilityChanged !== DX.abstract
                },
                _clean: $.noop,
                _modelByElement: $.noop,
                _invalidate: function() {
                    if (!this._updateLockCount)
                        throw Error("Invalidate called outside update transaction");
                    this._requireRefresh = true
                },
                _refresh: function() {
                    this._clean();
                    this._render()
                },
                _dispose: function() {
                    this._clean();
                    this._detachWindowResizeCallback();
                    this.optionChanged.empty();
                    this.disposing.fireWith(this).empty()
                },
                _detachWindowResizeCallback: function() {
                    if (this._isDimensionChangeSupported())
                        windowResizeCallbacks.remove(this._windowResizeCallBack)
                },
                _toggleRTLDirection: function(rtl) {
                    this._element().toggleClass(RTL_DIRECTION_CLASS, rtl)
                },
                _createAction: function(actionSource, config) {
                    var that = this;
                    config = $.extend({}, config);
                    var element = config.element || that._element(),
                        model = that._modelByElement(element);
                    config.context = model || that;
                    config.component = that;
                    var action = new DX.Action(actionSource, config);
                    return function(e) {
                            if (!arguments.length)
                                e = {};
                            if (e instanceof $.Event)
                                throw Error("Action must be executed with jQuery.Event like action({ jQueryEvent: event })");
                            if (!$.isPlainObject(e))
                                e = {actionValue: e};
                            return action.execute.call(action, $.extend(e, {
                                    component: that,
                                    element: element,
                                    model: model
                                }))
                        }
                },
                _createActionByOption: function(optionName, config) {
                    if (typeof optionName !== "string")
                        throw Error("Option name type is unexpected");
                    this._suppressDeprecatedWarnings();
                    var action = this._createAction(this.option(optionName), config);
                    this._resumeDeprecatedWarnings();
                    return action
                },
                _optionChanged: function(name, value, prevValue) {
                    if (name === "rtlEnabled")
                        this._invalidate()
                },
                _element: function() {
                    return this._$element
                },
                endUpdate: function() {
                    var requireRender = !this._initializing && !this._initialized;
                    this.callBase.apply(this, arguments);
                    if (!this._updateLockCount)
                        if (requireRender)
                            this._render();
                        else if (this._requireRefresh) {
                            this._requireRefresh = false;
                            this._refresh()
                        }
                }
            });
        var registerComponent = function(name, componentClass) {
                componentClass.redefine({_attachInstanceToElement: function($element) {
                        $element.data(name, this);
                        if (!$element.data(COMPONENT_NAMES_DATA_KEY))
                            $element.data(COMPONENT_NAMES_DATA_KEY, []);
                        $element.data(COMPONENT_NAMES_DATA_KEY).push(name)
                    }});
                componentClass.prototype.NAMESPACE[name] = componentClass;
                componentClass.prototype.NAME = name;
                componentClass.defaultOptions = function(rule) {
                    componentClass.prototype._customRules = componentClass.prototype._customRules || [];
                    componentClass.prototype._customRules.push(rule)
                };
                $.fn[name] = function(options) {
                    var isMemberInvoke = typeof options === "string",
                        result;
                    if (isMemberInvoke) {
                        var memberName = options,
                            memberArgs = $.makeArray(arguments).slice(1);
                        this.each(function() {
                            var instance = $(this).data(name);
                            if (!instance)
                                throw Error(DX.utils.stringFormat("Component {0} has not been initialized on this element", name));
                            var member = instance[memberName],
                                memberValue = member.apply(instance, memberArgs);
                            if (result === undefined)
                                result = memberValue
                        })
                    }
                    else {
                        this.each(function() {
                            var instance = $(this).data(name);
                            if (instance)
                                instance.option(options);
                            else
                                new componentClass(this, options)
                        });
                        result = this
                    }
                    return result
                }
            };
        var getComponents = function(element) {
                element = $(element);
                var names = element.data(COMPONENT_NAMES_DATA_KEY);
                if (!names)
                    return [];
                return $.map(names, function(name) {
                        return element.data(name)
                    })
            };
        var disposeComponents = function() {
                $.each(getComponents(this), function() {
                    this._dispose()
                })
            };
        var originalCleanData = $.cleanData;
        $.cleanData = function(element) {
            $.each(element, disposeComponents);
            return originalCleanData.apply(this, arguments)
        };
        registerComponent("DOMComponent", DOMComponent);
        DX.registerComponent = registerComponent
    })(jQuery, DevExpress);
    /*! Module core, file social.js */
    DevExpress.social = {};
    /*! Module core, file facebook.js */
    (function($, DX, undefined) {
        function notifyDeprecated() {
            DX.utils.logger.warn("DevExpress.social API is deprecated. Use official Facebook library instead")
        }
        var social = DX.social;
        var location = window.location,
            navigator = window.navigator,
            encodeURIComponent = window.encodeURIComponent,
            decodeURIComponent = window.decodeURIComponent,
            iosStandaloneMode = navigator.standalone,
            cordovaMode = false;
        if (window.cordova)
            $(document).on("deviceready", function() {
                cordovaMode = true
            });
        var ACCESS_TOKEN_KEY = "dx-facebook-access-token",
            IOS_STANDALONE_STEP1_KEY = "dx-facebook-step1",
            IOS_STANDALONE_STEP2_KEY = "dx-facebook-step2";
        var accessToken = null,
            expires = null,
            connectionChanged = $.Callbacks();
        var pendingLoginRedirectUrl;
        var isConnected = function() {
                return !!accessToken
            };
        var getAccessTokenObject = function() {
                return {
                        accessToken: accessToken,
                        expiresIn: accessToken ? expires : 0
                    }
            };
        var FB = social.Facebook = {
                loginRedirectUrl: "FacebookLoginCallback.html",
                connectionChanged: connectionChanged,
                isConnected: isConnected,
                getAccessTokenObject: getAccessTokenObject,
                jsonp: false
            };
        var login = function(appId, options) {
                notifyDeprecated();
                options = options || {};
                if (cordovaMode)
                    pendingLoginRedirectUrl = "https://www.facebook.com/connect/login_success.html";
                else
                    pendingLoginRedirectUrl = formatLoginRedirectUrl();
                var scope = (options.permissions || []).join(),
                    url = "https://www.facebook.com/dialog/oauth?display=popup&client_id=" + appId + "&redirect_uri=" + encodeURIComponent(pendingLoginRedirectUrl) + "&scope=" + encodeURIComponent(scope) + "&response_type=token";
                if (iosStandaloneMode)
                    putData(IOS_STANDALONE_STEP1_KEY, location.href);
                if (cordovaMode)
                    startLogin_cordova(url);
                else
                    startLogin_browser(url)
            };
        var formatLoginRedirectUrl = function() {
                var pathSegments = location.pathname.split(/\//g);
                pathSegments.pop();
                pathSegments.push(FB.loginRedirectUrl);
                return location.protocol + "//" + location.host + pathSegments.join("/")
            };
        var startLogin_browser = function(loginUrl) {
                var width = 512,
                    height = 320,
                    left = (screen.width - width) / 2,
                    top = (screen.height - height) / 2;
                window.open(loginUrl, null, "width=" + width + ",height=" + height + ",toolbar=0,scrollbars=0,status=0,resizable=0,menuBar=0,left=" + left + ",top=" + top)
            };
        var startLogin_cordova = function(loginUrl) {
                var ref = window.open(loginUrl, "_blank");
                ref.addEventListener('exit', function(event) {
                    pendingLoginRedirectUrl = null
                });
                ref.addEventListener('loadstop', function(event) {
                    var url = unescape(event.url);
                    if (url.indexOf(pendingLoginRedirectUrl) === 0) {
                        ref.close();
                        _processLoginRedirectUrl(url)
                    }
                })
            };
        var handleLoginRedirect = function() {
                var opener = window.opener;
                if (iosStandaloneMode) {
                    putData(IOS_STANDALONE_STEP2_KEY, location.href);
                    location.href = getData(IOS_STANDALONE_STEP1_KEY)
                }
                else if (opener && opener.DevExpress) {
                    opener.DevExpress.social.Facebook._processLoginRedirectUrl(location.href);
                    window.close()
                }
            };
        var _processLoginRedirectUrl = function(url) {
                var params = parseUrlFragment(url);
                expires = params.expires_in;
                changeToken(params.access_token);
                pendingLoginRedirectUrl = null
            };
        var parseUrlFragment = function(url) {
                var hash = url.split("#")[1];
                if (!hash)
                    return {};
                var pairs = hash.split(/&/g),
                    result = {};
                $.each(pairs, function(i) {
                    var splitPair = this.split("=");
                    result[splitPair[0]] = decodeURIComponent(splitPair[1])
                });
                return result
            };
        var logout = function() {
                notifyDeprecated();
                changeToken(null)
            };
        var changeToken = function(value) {
                if (value === accessToken)
                    return;
                accessToken = value;
                putData(ACCESS_TOKEN_KEY, value);
                connectionChanged.fire(!!value)
            };
        var api = function(resource, method, params) {
                notifyDeprecated();
                if (!isConnected())
                    throw Error("Not connected");
                if (typeof method !== "string") {
                    params = method;
                    method = undefined
                }
                method = (method || "get").toLowerCase();
                var d = $.Deferred();
                var args = arguments;
                $.ajax({
                    url: "https://graph.facebook.com/" + resource,
                    type: method,
                    data: $.extend({access_token: accessToken}, params),
                    dataType: FB.jsonp && method === "get" ? "jsonp" : "json"
                }).done(function(response) {
                    response = response || simulateErrorResponse();
                    if (response.error)
                        d.reject(response.error);
                    else
                        d.resolve(response)
                }).fail(function(xhr) {
                    var response;
                    try {
                        response = $.parseJSON(xhr.responseText);
                        var tries = args[3] || 0;
                        if (tries++ < 3 && response.error.code == 190 && response.error.error_subcode == 466) {
                            setTimeout(function() {
                                api(resource, method, params, tries).done(function(result) {
                                    d.resolve(result)
                                }).fail(function(error) {
                                    d.reject(error)
                                })
                            }, 500);
                            return
                        }
                    }
                    catch(x) {
                        response = simulateErrorResponse()
                    }
                    d.reject(response.error)
                });
                return d.promise()
            };
        var simulateErrorResponse = function() {
                return {error: {message: "Unknown error"}}
            };
        var ensureStorageBackend = function() {
                if (!hasStorageBackend())
                    throw Error("HTML5 sessionStorage or jQuery.cookie plugin is required");
            };
        var hasStorageBackend = function() {
                return !!($.cookie || window.sessionStorage)
            };
        var putData = function(key, data) {
                ensureStorageBackend();
                data = JSON.stringify(data);
                if (window.sessionStorage)
                    if (data === null)
                        sess.removeItem(key);
                    else
                        sessionStorage.setItem(key, data);
                else
                    $.cookie(key, data)
            };
        var getData = function(key) {
                ensureStorageBackend();
                try {
                    return JSON.parse(window.sessionStorage ? sessionStorage.getItem(key) : $.cookie(key))
                }
                catch(x) {
                    return null
                }
            };
        if (hasStorageBackend())
            accessToken = getData(ACCESS_TOKEN_KEY);
        if (iosStandaloneMode) {
            var url = getData(IOS_STANDALONE_STEP2_KEY);
            if (url) {
                _processLoginRedirectUrl(url);
                putData(IOS_STANDALONE_STEP1_KEY, null);
                putData(IOS_STANDALONE_STEP2_KEY, null)
            }
        }
        $.extend(FB, {
            login: login,
            logout: logout,
            handleLoginRedirect: handleLoginRedirect,
            _processLoginRedirectUrl: _processLoginRedirectUrl,
            api: api
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.js */
    (function($, DX, undefined) {
        var ui = DX.ui = {};
        var TemplateProvider = DX.Class.inherit({
                getTemplateClass: function() {
                    return Template
                },
                supportDefaultTemplate: function() {
                    return false
                },
                getDefaultTemplate: function() {
                    return null
                }
            });
        var Template = DX.Class.inherit({
                ctor: function(element) {
                    this._template = this._element = $(element).detach()
                },
                render: function(container) {
                    var renderedTemplate = this._template.clone();
                    container.append(renderedTemplate);
                    return renderedTemplate
                },
                dispose: $.noop
            });
        var GESTURE_LOCK_KEY = "dxGestureLock";
        DX.registerActionExecutor({
            designMode: {validate: function(e) {
                    if (DX.designMode)
                        e.cancel = true
                }},
            gesture: {validate: function(e) {
                    if (!e.args.length)
                        return;
                    var args = e.args[0],
                        element = args.itemElement || args.element;
                    while (element && element.length) {
                        if (element.data(GESTURE_LOCK_KEY)) {
                            e.cancel = true;
                            break
                        }
                        element = element.parent()
                    }
                }},
            disabled: {validate: function(e) {
                    if (!e.args.length)
                        return;
                    var args = e.args[0],
                        element = args.itemElement || args.element;
                    if (element && element.is(".dx-state-disabled, .dx-state-disabled *"))
                        e.cancel = true
                }}
        });
        $.extend(ui, {
            TemplateProvider: TemplateProvider,
            Template: Template,
            initViewport: function() {
                DX.utils.logger.warn("DevExpress.ui.initViewport is deprecated. Use DX.utils.initMobileViewport instead");
                DX.utils.initMobileViewport()
            }
        });
        ui.__internals = ui.__internals || {};
        $.extend(ui.__internals, {Template: Template})
    })(jQuery, DevExpress);
    /*! Module core, file ko.components.js */
    (function($, DX, undefined) {
        if (!DX.support.hasKo)
            return;
        var ko = window.ko,
            ui = DX.ui,
            LOCKS_DATA_KEY = "dxKoLocks",
            CREATED_WITH_KO_DATA_KEY = "dxKoCreation";
        var Locks = function() {
                var info = {};
                var currentCount = function(lockName) {
                        return info[lockName] || 0
                    };
                return {
                        obtain: function(lockName) {
                            info[lockName] = currentCount(lockName) + 1
                        },
                        release: function(lockName) {
                            var count = currentCount(lockName);
                            if (count < 1)
                                throw Error("Not locked");
                            if (count === 1)
                                delete info[lockName];
                            else
                                info[lockName] = count - 1
                        },
                        locked: function(lockName) {
                            return currentCount(lockName) > 0
                        }
                    }
            };
        var registerComponentKoBinding = function(componentName) {
                ko.bindingHandlers[componentName] = {init: function(domNode, valueAccessor) {
                        var element = $(domNode),
                            ctorOptions = {},
                            optionNameToModelMap = {};
                        var applyModelValueToOption = function(optionName, modelValue) {
                                var component = element.data(componentName),
                                    locks = element.data(LOCKS_DATA_KEY),
                                    optionValue = ko.utils.unwrapObservable(modelValue);
                                if (ko.isWriteableObservable(modelValue))
                                    optionNameToModelMap[optionName] = modelValue;
                                if (component) {
                                    if (locks.locked(optionName))
                                        return;
                                    locks.obtain(optionName);
                                    try {
                                        component.option(optionName, optionValue)
                                    }
                                    finally {
                                        locks.release(optionName)
                                    }
                                }
                                else
                                    ctorOptions[optionName] = optionValue
                            };
                        var handleOptionChanged = function(optionName, optionValue) {
                                if (!(optionName in optionNameToModelMap))
                                    return;
                                var element = this._$element,
                                    locks = element.data(LOCKS_DATA_KEY);
                                if (locks.locked(optionName))
                                    return;
                                locks.obtain(optionName);
                                try {
                                    optionNameToModelMap[optionName](optionValue)
                                }
                                finally {
                                    locks.release(optionName)
                                }
                            };
                        var createComponent = function() {
                                element.data(CREATED_WITH_KO_DATA_KEY, true);
                                element[componentName](ctorOptions);
                                ctorOptions = null;
                                element.data(LOCKS_DATA_KEY, new Locks);
                                element.data(componentName).optionChanged.add(handleOptionChanged)
                            };
                        ko.computed(function() {
                            var component = element.data(componentName);
                            if (component)
                                component.beginUpdate();
                            $.each(ko.unwrap(valueAccessor()), function(modelName, modelValueExpr) {
                                ko.computed(function() {
                                    applyModelValueToOption(modelName, modelValueExpr)
                                }, null, {disposeWhenNodeIsRemoved: domNode})
                            });
                            if (component)
                                component.endUpdate();
                            else
                                createComponent()
                        }, null, {disposeWhenNodeIsRemoved: domNode});
                        return {controlsDescendantBindings: ui[componentName] && ui[componentName].subclassOf(ui.Widget)}
                    }}
            };
        var KoComponent = DX.DOMComponent.inherit({_modelByElement: function(element) {
                    if (element.length)
                        return ko.dataFor(element.get(0))
                }});
        var originalRegisterComponent = DX.registerComponent;
        var registerKoComponent = function(name, componentClass) {
                originalRegisterComponent(name, componentClass);
                registerComponentKoBinding(name)
            };
        ko.bindingHandlers.dxAction = {update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
                var $element = $(element);
                var unwrappedValue = ko.utils.unwrapObservable(valueAccessor()),
                    actionSource = unwrappedValue,
                    actionOptions = {context: element};
                if (unwrappedValue.execute) {
                    actionSource = unwrappedValue.execute;
                    $.extend(actionOptions, unwrappedValue)
                }
                var action = new DX.Action(actionSource, actionOptions);
                $element.off(".dxActionBinding").on("dxclick.dxActionBinding", function(e) {
                    action.execute({
                        element: $element,
                        model: viewModel,
                        evaluate: function(expression) {
                            var context = viewModel;
                            if (expression.length > 0 && expression[0] === "$")
                                context = ko.contextFor(element);
                            var getter = DX.data.utils.compileGetter(expression);
                            return getter(context)
                        },
                        jQueryEvent: e
                    });
                    if (!actionOptions.bubbling)
                        e.stopPropagation()
                })
            }};
        var cleanKoData = function(element, andSelf) {
                var cleanNode = function() {
                        ko.cleanNode(this)
                    };
                if (andSelf)
                    element.each(cleanNode);
                else
                    element.find("*").each(cleanNode)
            };
        var originalEmpty = $.fn.empty;
        $.fn.empty = function() {
            cleanKoData(this, false);
            return originalEmpty.apply(this, arguments)
        };
        var originalRemove = $.fn.remove;
        $.fn.remove = function(selector, keepData) {
            if (!keepData) {
                var subject = this;
                if (selector)
                    subject = subject.filter(selector);
                cleanKoData(subject, true)
            }
            return originalRemove.call(this, selector, keepData)
        };
        var originalHtml = $.fn.html;
        $.fn.html = function(value) {
            if (typeof value === "string")
                cleanKoData(this, false);
            return originalHtml.apply(this, arguments)
        };
        DX.registerComponent = registerKoComponent;
        registerKoComponent("DOMComponent", KoComponent)
    })(jQuery, DevExpress);
    /*! Module core, file ng.components.js */
    (function($, DX, undefined) {
        if (!DX.support.hasNg)
            return;
        var ui = DX.ui,
            compileSetter = DX.data.utils.compileSetter,
            compileGetter = DX.data.utils.compileGetter;
        var CREATED_WITH_NG_DATA_KEY = "dxNgCreation",
            TEMPLATES_DATA_KEY = "dxTemplates",
            COMPILER_DATA_KEY = "dxNgCompiler",
            DEFAULT_COMPILER_DATA_KEY = "dxDefaultCompilerGetter",
            ANONYMOUS_TEMPLATE_NAME = "template";
        var phoneJsModule = DX.ng.module;
        var ComponentBuilder = DX.Class.inherit({
                ctor: function(options) {
                    this._componentName = options.componentName;
                    this._compile = options.compile;
                    this._$element = options.$element;
                    this._componentDisposing = $.Callbacks();
                    this._$templates = this._extractTemplates()
                },
                init: function(options) {
                    this._scope = options.scope;
                    this._$element = options.$element;
                    this._ngOptions = options.ngOptions;
                    this._$element.data(CREATED_WITH_NG_DATA_KEY, true);
                    if (options.ngOptions.data)
                        this._initDataScope(options.ngOptions.data)
                },
                initDefaultCompilerGetter: function() {
                    var that = this;
                    that._$element.data(DEFAULT_COMPILER_DATA_KEY, function($template) {
                        return that._compilerByTemplate($template)
                    })
                },
                initTemplateCompilers: function() {
                    var that = this;
                    if (this._$templates)
                        this._$templates.each(function(i, template) {
                            $(template).data(COMPILER_DATA_KEY, that._compilerByTemplate(template))
                        })
                },
                initComponentWithBindings: function() {
                    this._initComponent(this._scope);
                    this._initComponentBindings()
                },
                _initDataScope: function(data) {
                    if (typeof data === "string") {
                        var dataStr = data,
                            rootScope = this._scope;
                        data = rootScope.$eval(data);
                        this._scope = rootScope.$new();
                        this._synchronizeDataScopes(rootScope, this._scope, data, dataStr)
                    }
                    $.extend(this._scope, data)
                },
                _synchronizeDataScopes: function(parentScope, childScope, data, parentPrefix) {
                    var that = this;
                    $.each(data, function(fieldPath) {
                        that._synchronizeScopeField({
                            parentScope: parentScope,
                            childScope: childScope,
                            fieldPath: fieldPath,
                            parentPrefix: parentPrefix
                        })
                    })
                },
                _initComponent: function(scope) {
                    this._component = this._$element[this._componentName](this._evalOptions(scope)).data(this._componentName)
                },
                _initComponentBindings: function() {
                    var that = this,
                        optionDependencies = {};
                    if (that._ngOptions.bindingOptions)
                        $.each(that._ngOptions.bindingOptions, function(optionPath, valuePath) {
                            var separatorIndex = optionPath.search(/\[|\./),
                                optionForSubscribe = separatorIndex > -1 ? optionPath.substring(0, separatorIndex) : optionPath;
                            if (!optionDependencies[optionForSubscribe])
                                optionDependencies[optionForSubscribe] = {};
                            optionDependencies[optionForSubscribe][optionPath] = valuePath;
                            var clearWatcher = that._scope.$watch(valuePath, function(newValue, oldValue) {
                                    if (newValue !== oldValue)
                                        that._component.option(optionPath, newValue)
                                }, true);
                            that._component.disposing.add(function() {
                                clearWatcher();
                                that._componentDisposing.fire()
                            })
                        });
                    that._component.optionChanged.add(function(optionName, optionValue) {
                        if (that._scope.$root.$$phase === "$digest" || !optionDependencies || !optionDependencies[optionName])
                            return;
                        safeApply(function(scope) {
                            $.each(optionDependencies[optionName], function(optionPath, valuePath) {
                                var setter = compileSetter(valuePath),
                                    getter = compileGetter(optionPath);
                                var tmpData = {};
                                tmpData[optionName] = optionValue;
                                setter(scope, getter(tmpData))
                            })
                        }, that._scope)
                    })
                },
                _extractTemplates: function() {
                    if (this._$element.data(TEMPLATES_DATA_KEY))
                        return this._$element.data(TEMPLATES_DATA_KEY);
                    var $templates;
                    if (ui[this._componentName] && ui[this._componentName].subclassOf(ui.Widget) && $.trim(this._$element.html())) {
                        var isAnonymousTemplate = !this._$element.children().first().attr("data-options");
                        if (isAnonymousTemplate)
                            $templates = $("<div/>").attr("data-options", "dxTemplate: { name: '" + ANONYMOUS_TEMPLATE_NAME + "' }").append(this._$element.contents());
                        else
                            $templates = this._$element.children().detach();
                        this._$element.data(TEMPLATES_DATA_KEY, $templates)
                    }
                    return $templates
                },
                _compilerByTemplate: function(template) {
                    var that = this,
                        scopeItemsPath = this._getScopeItemsPath();
                    return function(data, index) {
                            var $resultMarkup = $(template).clone(),
                                templateScope;
                            if (data !== undefined) {
                                var dataIsScope = data.$id,
                                    templateScope = dataIsScope ? data : that._createScopeWithData(data);
                                $resultMarkup.on("$destroy", function() {
                                    var destroyAlreadyCalled = !templateScope.$parent;
                                    if (destroyAlreadyCalled)
                                        return;
                                    templateScope.$destroy()
                                })
                            }
                            else
                                templateScope = that._scope;
                            if (scopeItemsPath)
                                that._synchronizeScopes(templateScope, scopeItemsPath, index);
                            safeApply(that._compile($resultMarkup), templateScope);
                            return $resultMarkup
                        }
                },
                _getScopeItemsPath: function() {
                    if (ui[this._componentName].subclassOf(ui.CollectionContainerWidget) && this._ngOptions.bindingOptions)
                        return this._ngOptions.bindingOptions.items
                },
                _createScopeWithData: function(data) {
                    var newScope = this._scope.$new(true);
                    if (typeof data === "object")
                        $.extend(newScope, data);
                    else
                        newScope.scopeValue = data;
                    return newScope
                },
                _synchronizeScopes: function(itemScope, parentPrefix, itemIndex) {
                    var that = this,
                        item = compileGetter(parentPrefix + "[" + itemIndex + "]")(this._scope);
                    if (!$.isPlainObject(item))
                        item = {scopeValue: item};
                    $.each(item, function(itemPath) {
                        that._synchronizeScopeField({
                            parentScope: that._scope,
                            childScope: itemScope,
                            fieldPath: itemPath,
                            parentPrefix: parentPrefix,
                            itemIndex: itemIndex
                        })
                    })
                },
                _synchronizeScopeField: function(args) {
                    var parentScope = args.parentScope,
                        childScope = args.childScope,
                        fieldPath = args.fieldPath,
                        parentPrefix = args.parentPrefix,
                        itemIndex = args.itemIndex;
                    var innerPathSuffix = fieldPath === "scopeValue" ? "" : "." + fieldPath,
                        collectionField = itemIndex !== undefined,
                        optionOuterBag = [parentPrefix],
                        optionOuterPath;
                    if (collectionField)
                        optionOuterBag.push("[", itemIndex, "]");
                    optionOuterBag.push(innerPathSuffix);
                    optionOuterPath = optionOuterBag.join("");
                    var clearParentWatcher = parentScope.$watch(optionOuterPath, function(newValue, oldValue) {
                            if (newValue !== oldValue)
                                compileSetter(fieldPath)(childScope, newValue)
                        });
                    var clearItemWatcher = childScope.$watch(fieldPath, function(newValue, oldValue) {
                            if (newValue !== oldValue) {
                                if (collectionField && !compileGetter(parentPrefix)(parentScope)[itemIndex]) {
                                    clearItemWatcher();
                                    return
                                }
                                compileSetter(optionOuterPath)(parentScope, newValue)
                            }
                        });
                    this._componentDisposing.add([clearParentWatcher, clearItemWatcher])
                },
                _evalOptions: function(scope) {
                    var result = $.extend({}, this._ngOptions);
                    delete result.data;
                    delete result.bindingOptions;
                    if (this._ngOptions.bindingOptions)
                        $.each(this._ngOptions.bindingOptions, function(key, value) {
                            result[key] = scope.$eval(value)
                        });
                    return result
                }
            });
        var safeApply = function(func, scope) {
                if (scope.$root.$$phase)
                    func(scope);
                else
                    scope.$apply(function() {
                        func(scope)
                    })
            };
        var NgComponent = DX.DOMComponent.inherit({
                _modelByElement: function(element) {
                    if (element.length)
                        return element.scope()
                },
                _createActionByOption: function() {
                    var action = this.callBase.apply(this, arguments);
                    var component = this,
                        wrappedAction = function() {
                            var that = this,
                                scope = component._modelByElement(component._element()),
                                args = arguments;
                            if (!scope || scope.$root.$$phase)
                                return action.apply(that, args);
                            return scope.$apply(function() {
                                    return action.apply(that, args)
                                })
                        };
                    return wrappedAction
                }
            });
        var originalRegisterComponent = DX.registerComponent;
        var registerNgComponent = function(componentName, componentClass) {
                originalRegisterComponent(componentName, componentClass);
                phoneJsModule.directive(componentName, ["$compile", function(compile) {
                        return {
                                restrict: "A",
                                compile: function($element) {
                                    var componentBuilder = new ComponentBuilder({
                                            componentName: componentName,
                                            compile: compile,
                                            $element: $element
                                        });
                                    return function(scope, $element, attrs) {
                                            componentBuilder.init({
                                                scope: scope,
                                                $element: $element,
                                                ngOptions: attrs[componentName] ? scope.$eval(attrs[componentName]) : {}
                                            });
                                            componentBuilder.initTemplateCompilers();
                                            componentBuilder.initDefaultCompilerGetter();
                                            componentBuilder.initComponentWithBindings()
                                        }
                                }
                            }
                    }])
            };
        DX.registerComponent = registerNgComponent;
        registerNgComponent("DOMComponent", NgComponent)
    })(jQuery, DevExpress);
    /*! Module core, file ko.templates.js */
    (function($, DX, undefined) {
        if (!DX.support.hasKo)
            return;
        var ko = window.ko,
            ui = DX.ui,
            CREATED_WITH_KO_DATA_KEY = "dxKoCreation";
        var KoTemplate = ui.Template.inherit({
                ctor: function(element) {
                    this.callBase.apply(this, arguments);
                    this._template = $("<div>").append(element);
                    this._registerKoTemplate()
                },
                _cleanTemplateElement: function() {
                    this._element.each(function() {
                        ko.cleanNode(this)
                    })
                },
                _registerKoTemplate: function() {
                    var template = this._template.get(0);
                    new ko.templateSources.anonymousTemplate(template)['nodes'](template)
                },
                render: function(container, data) {
                    data = data !== undefined ? data : ko.dataFor(container.get(0)) || {};
                    var containerBindingContext = ko.contextFor(container[0]);
                    var bindingContext = containerBindingContext ? containerBindingContext.createChildContext(data) : data;
                    var renderBag = $("<div />").appendTo(container);
                    ko.renderTemplate(this._template.get(0), bindingContext, null, renderBag.get(0));
                    var result = renderBag.contents();
                    container.append(result);
                    renderBag.remove();
                    return result
                },
                dispose: function() {
                    this._template.remove()
                }
            });
        var KoTemplateProvider = ui.TemplateProvider.inherit({
                getTemplateClass: function(widget) {
                    return this._createdWithKo(widget) ? KoTemplate : this.callBase(widget)
                },
                supportDefaultTemplate: function(widget) {
                    return this._createdWithKo(widget) ? true : this.callBase(widget)
                },
                getDefaultTemplate: function(widget) {
                    if (this._createdWithKo(widget))
                        return defaultKoTemplate(widget.NAME)
                },
                _createdWithKo: function(widget) {
                    return !!widget._element().data(CREATED_WITH_KO_DATA_KEY)
                }
            });
        var defaultKoTemplate = function() {
                var cache = {};
                return function(widgetName) {
                        if (!DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName])
                            widgetName = "base";
                        if (!cache[widgetName]) {
                            var html = DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName](),
                                markup = DX.utils.createMarkupFromString(html);
                            cache[widgetName] = new KoTemplate(markup)
                        }
                        return cache[widgetName]
                    }
            }();
        var createElementWithBindAttr = function(tagName, bindings, closeTag, additionalProperties) {
                closeTag = closeTag === undefined ? true : closeTag;
                var bindAttr = $.map(bindings, function(value, key) {
                        return key + ":" + value
                    }).join(",");
                additionalProperties = additionalProperties || "";
                return "<" + tagName + " data-bind=\"" + bindAttr + "\" " + additionalProperties + ">" + (closeTag ? "</" + tagName + ">" : "")
            };
        var defaultKoTemplateBasicBindings = {css: "{ 'dx-state-disabled': $data.disabled, 'dx-state-invisible': !($data.visible === undefined || ko.unwrap($data.visible)) }"};
        var DEFAULT_ITEM_TEMPLATE_GENERATORS = {base: function() {
                    var template = [createElementWithBindAttr("div", defaultKoTemplateBasicBindings, false)],
                        htmlBinding = createElementWithBindAttr("div", {html: "html"}),
                        textBinding = createElementWithBindAttr("div", {text: "text"}),
                        primitiveBinding = createElementWithBindAttr("div", {text: "String($data)"});
                    template.push("<!-- ko if: $data.html && !$data.text -->", htmlBinding, "<!-- /ko -->", "<!-- ko if: !$data.html && $data.text -->", textBinding, "<!-- /ko -->", "<!-- ko ifnot: $.isPlainObject($data) -->", primitiveBinding, "<!-- /ko -->", "</div>");
                    return template.join("")
                }};
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxPivotTabs = function() {
            var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
                titleBinding = createElementWithBindAttr("span", {text: "title"});
            var divInnerStart = template.indexOf(">") + 1,
                divInnerFinish = template.length - 6;
            template = [template.substring(0, divInnerStart), titleBinding, template.substring(divInnerFinish, template.length)];
            return template.join("")
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxPanorama = function() {
            var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
                headerBinding = createElementWithBindAttr("div", {text: "header"}, true, 'class="dx-panorama-item-header"');
            var divInnerStart = template.indexOf(">") + 1;
            template = [template.substring(0, divInnerStart), "<!-- ko if: $data.header -->", headerBinding, "<!-- /ko -->", template.substring(divInnerStart, template.length)];
            return template.join("")
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxList = function() {
            var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
                keyBinding = createElementWithBindAttr("div", {text: "key"});
            template = [template.substring(0, template.length - 6), "<!-- ko if: $data.key -->" + keyBinding + "<!-- /ko -->", "</div>"];
            return template.join("")
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxToolbar = function() {
            var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base();
            template = [template.substring(0, template.length - 6), "<!-- ko if: $data.widget -->"];
            $.each(["button", "tabs", "dropDownMenu"], function() {
                var bindingName = DX.inflector.camelize(["dx", "-", this].join("")),
                    bindingObj = {};
                bindingObj[bindingName] = "$data.options";
                template.push("<!-- ko if: $data.widget === '", this, "' -->", createElementWithBindAttr("div", bindingObj), "<!-- /ko -->")
            });
            template.push("<!-- /ko -->");
            return template.join("")
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxGallery = function() {
            var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
                primitiveBinding = createElementWithBindAttr("div", {text: "String($data)"}),
                imgBinding = createElementWithBindAttr("img", {attr: "{ src: String($data) }"}, false);
            template = template.replace(primitiveBinding, imgBinding);
            return template
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs = function() {
            var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
                baseTextBinding = createElementWithBindAttr("div", {text: "text"}),
                iconBinding = createElementWithBindAttr("span", {
                    attr: "{ 'class': 'dx-icon-' + $data.icon }",
                    css: "{ 'dx-icon': true }"
                }),
                iconSrcBinding = createElementWithBindAttr("img", {
                    attr: "{ src: $data.iconSrc }",
                    css: "{ 'dx-icon': true }"
                }, false),
                textBinding = "<!-- ko if: $data.icon -->" + iconBinding + "<!-- /ko -->" + "<!-- ko if: !$data.icon && $data.iconSrc -->" + iconSrcBinding + "<!-- /ko -->" + "<span class=\"dx-tab-text\" data-bind=\"text: $data.text\"></span>";
            template = template.replace("<!-- ko if: !$data.html && $data.text -->", "<!-- ko if: !$data.html && ($data.text || $data.icon || $data.iconSrc) -->").replace(baseTextBinding, textBinding);
            return template
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxActionSheet = function() {
            return createElementWithBindAttr("div", {dxButton: "{ text: $data.text, clickAction: $data.clickAction, type: $data.type, disabled: !!ko.unwrap($data.disabled) }"})
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxNavBar = DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs;
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxMenu = function() {
            var template = [createElementWithBindAttr("div", defaultKoTemplateBasicBindings, false)],
                iconBinding = createElementWithBindAttr("span", {
                    attr: "{ 'class': + 'dx-icon-' + $data.icon }",
                    css: "{ 'dx-icon': true }"
                }),
                iconSrcBinding = createElementWithBindAttr("img", {
                    attr: "{ src: $data.iconSrc }",
                    css: "{ 'dx-icon': true }"
                }),
                textBinding = createElementWithBindAttr("span", {
                    text: "text",
                    css: "{ 'dx-menu-item-text': true }"
                }),
                primitiveBinding = createElementWithBindAttr("span", {
                    text: "String($data)",
                    css: "{ 'dx-menu-item-text': true }"
                });
            template.push('<div class="dx-menu-item-content">', '<!-- ko if: $data.icon -->', iconBinding, '<!-- /ko -->', '<!-- ko if: !$data.icon && $data.iconSrc -->', iconSrcBinding, '<!-- /ko -->', '<!-- ko if: $.isPlainObject($data) -->', textBinding, '<!-- /ko -->', '<!-- ko ifnot: $.isPlainObject($data) -->', primitiveBinding, '<!-- /ko -->', '<!-- ko if: $data.items --><span class="dx-menu-item-popout"></span><!-- /ko -->', '</div>', '</div>');
            return template.join("")
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxContextMenu = DEFAULT_ITEM_TEMPLATE_GENERATORS.dxMenu;
        $.extend(ui, {
            TemplateProvider: KoTemplateProvider,
            Template: KoTemplate,
            defaultTemplate: defaultKoTemplate
        });
        ui.__internals = ui.__internals || {};
        $.extend(ui.__internals, {KoTemplate: KoTemplate})
    })(jQuery, DevExpress);
    /*! Module core, file ng.templates.js */
    (function($, DX, undefined) {
        if (!DX.support.hasNg)
            return;
        var ui = DX.ui;
        var CREATED_WITH_NG_DATA_KEY = "dxNgCreation",
            COMPILER_DATA_KEY = "dxNgCompiler",
            DEFAULT_COMPILER_DATA_KEY = "dxDefaultCompilerGetter";
        var NgTemplate = ui.Template.inherit({
                ctor: function() {
                    this.callBase.apply(this, arguments);
                    this._compiler = this._template.data(COMPILER_DATA_KEY)
                },
                render: function(container, data, index) {
                    var compiler = this._compiler,
                        result = $.isFunction(compiler) ? compiler(data, index) : compiler;
                    container.append(result);
                    return result
                },
                setCompiler: function(compilerGetter) {
                    this._compiler = compilerGetter(this._element)
                }
            });
        var NgTemplateProvider = ui.TemplateProvider.inherit({
                getTemplateClass: function(widget) {
                    if (this._createdWithNg(widget))
                        return NgTemplate;
                    return this.callBase(widget)
                },
                supportDefaultTemplate: function(widget) {
                    return this._createdWithNg(widget) ? true : this.callBase(widget)
                },
                getDefaultTemplate: function(widget) {
                    if (this._createdWithNg(widget)) {
                        var compilerGetter = widget._element().data(DEFAULT_COMPILER_DATA_KEY),
                            template = defaultNgTemplate(widget.NAME);
                        template.setCompiler(compilerGetter);
                        return template
                    }
                },
                _createdWithNg: function(widget) {
                    return !!widget._element().data(CREATED_WITH_NG_DATA_KEY)
                }
            });
        var defaultNgTemplate = function() {
                var cache = {};
                return function(widgetName) {
                        if (!DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName])
                            widgetName = "base";
                        if (!cache[widgetName])
                            cache[widgetName] = DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName]();
                        return new NgTemplate(cache[widgetName])
                    }
            }();
        var baseElements = {
                container: function() {
                    return $("<div/>").attr("ng-class", "{ 'dx-state-invisible': !visible && visible != undefined, 'dx-state-disabled': !!disabled }")
                },
                html: function() {
                    return $("<div/>").attr("ng-if", "html").attr("ng-bind-html", "html")
                },
                text: function() {
                    return $("<div/>").attr("ng-if", "text").attr("ng-bind", "text")
                },
                primitive: function() {
                    return $("<div/>").attr("ng-if", "scopeValue").attr("ng-bind-html", "'' + scopeValue")
                }
            };
        var DEFAULT_ITEM_TEMPLATE_GENERATORS = {base: function() {
                    return baseElements.container().append(baseElements.html()).append(baseElements.text()).append(baseElements.primitive())
                }};
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxList = function() {
            return DEFAULT_ITEM_TEMPLATE_GENERATORS.base().append($("<div/>").attr("ng-if", "key").attr("ng-bind", "key"))
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxToolbar = function() {
            var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base();
            $.each(["button", "tabs", "dropDownMenu"], function(i, widgetName) {
                var bindingName = "dx-" + DX.inflector.dasherize(this);
                $("<div/>").attr("ng-if", "widget === '" + widgetName + "'").attr(bindingName, "options").appendTo(template)
            });
            return template
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxGallery = function() {
            return baseElements.container().append(baseElements.html()).append(baseElements.text()).append($("<img/>").attr("ng-if", "scopeValue").attr("ng-src", "{{'' + scopeValue}}"))
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs = function() {
            var container = baseElements.container();
            var text = $("<span/>").addClass("dx-tab-text").attr("ng-bind", "text"),
                icon = $("<span/>").attr("ng-if", "icon").addClass("dx-icon").attr("ng-class", "'dx-icon-' + icon").add(text.attr("ng-if", "icon")),
                iconSrc = $("<img/>").attr("ng-if", "iconSrc").addClass("dx-icon").attr("ng-src", "{{iconSrc}}").add(text.attr("ng-if", "iconSrc"));
            return container.append(baseElements.html()).append(icon).append(iconSrc).append(text.attr("ng-if", "text")).append(baseElements.primitive())
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxActionSheet = function() {
            return $("<div/>").attr("dx-button", "{ bindingOptions: { text: 'text', clickAction: 'clickAction', type: 'type', disabled: 'disabled' } }")
        };
        DEFAULT_ITEM_TEMPLATE_GENERATORS.dxNavBar = DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs;
        $.extend(ui, {
            Template: NgTemplate,
            TemplateProvider: NgTemplateProvider
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.themes.js */
    (function($, DX, undefined) {
        var DX_LINK_SELECTOR = "link[rel=dx-theme]",
            THEME_ATTR = "data-theme",
            ACTIVE_ATTR = "data-active";
        var context,
            $activeThemeLink,
            knownThemes,
            currentThemeName,
            pendingThemeName;
        var THEME_MARKER_PREFIX = "dx.";
        function readThemeMarker() {
            var element = $("<div></div>", context).addClass("dx-theme-marker").appendTo(context.documentElement),
                result;
            try {
                result = element.css("font-family");
                if (!result)
                    return null;
                result = result.replace(/["']/g, "");
                if (result.substr(0, THEME_MARKER_PREFIX.length) !== THEME_MARKER_PREFIX)
                    return null;
                return result.substr(THEME_MARKER_PREFIX.length)
            }
            finally {
                element.remove()
            }
        }
        function waitForThemeLoad(themeName, callback) {
            var timerId,
                waitStartTime;
            pendingThemeName = themeName;
            function handleLoaded() {
                pendingThemeName = null;
                callback()
            }
            if (isPendingThemeLoaded())
                handleLoaded();
            else {
                waitStartTime = $.now();
                timerId = setInterval(function() {
                    var isLoaded = isPendingThemeLoaded(),
                        isTimeout = !isLoaded && $.now() - waitStartTime > 15 * 1000;
                    if (isTimeout)
                        DX.utils.logger.warn("Theme loading timed out: " + pendingThemeName);
                    if (isLoaded || isTimeout) {
                        clearInterval(timerId);
                        handleLoaded()
                    }
                }, 10)
            }
        }
        function isPendingThemeLoaded() {
            return !pendingThemeName || readThemeMarker() === pendingThemeName
        }
        function processMarkup() {
            var $allThemeLinks = $(DX_LINK_SELECTOR, context);
            if (!$allThemeLinks.length)
                return;
            knownThemes = {};
            $activeThemeLink = $("<link rel=stylesheet>", context);
            $allThemeLinks.each(function() {
                var link = $(this, context),
                    fullThemeName = link.attr(THEME_ATTR),
                    url = link.attr("href"),
                    isActive = link.attr(ACTIVE_ATTR) === "true";
                knownThemes[fullThemeName] = {
                    url: url,
                    isActive: isActive
                }
            });
            $allThemeLinks.last().after($activeThemeLink);
            $allThemeLinks.remove()
        }
        function resolveFullThemeName(desiredThemeName) {
            var desiredThemeParts = desiredThemeName.split("."),
                result = null;
            if (knownThemes)
                $.each(knownThemes, function(knownThemeName, themeData) {
                    var knownThemeParts = knownThemeName.split(".");
                    if (knownThemeParts[0] !== desiredThemeParts[0])
                        return;
                    if (desiredThemeParts[1] && desiredThemeParts[1] !== knownThemeParts[1])
                        return;
                    if (!result || themeData.isActive)
                        result = knownThemeName;
                    if (themeData.isActive)
                        return false
                });
            return result
        }
        function initContext(newContext) {
            try {
                if (newContext !== context)
                    knownThemes = null
            }
            catch(x) {
                knownThemes = null
            }
            context = newContext
        }
        function init(options) {
            options = options || {};
            initContext(options.context || document);
            processMarkup();
            currentThemeName = undefined;
            current(options)
        }
        function current(options) {
            if (!arguments.length)
                return currentThemeName || readThemeMarker();
            options = options || {};
            if (typeof options === "string")
                options = {theme: options};
            var isAutoInit = options._autoInit,
                loadCallback = options.loadCallback,
                currentThemeData;
            currentThemeName = options.theme || currentThemeName;
            if (isAutoInit && !currentThemeName)
                currentThemeName = themeNameFromDevice(DX.devices.current());
            currentThemeName = resolveFullThemeName(currentThemeName);
            if (currentThemeName)
                currentThemeData = knownThemes[currentThemeName];
            if (currentThemeData) {
                $activeThemeLink.removeAttr("href");
                $activeThemeLink.attr("href", knownThemes[currentThemeName].url);
                if (loadCallback)
                    waitForThemeLoad(currentThemeName, loadCallback);
                else if (pendingThemeName)
                    pendingThemeName = currentThemeName
            }
            else if (isAutoInit) {
                if (loadCallback)
                    loadCallback()
            }
            else
                throw Error("Unknown theme: " + currentThemeName);
        }
        function themeNameFromDevice(device) {
            var themeName = device.platform,
                majorVersion = device.version && device.version[0];
            if (themeName === "ios" && (!majorVersion || majorVersion > 6))
                themeName += "7";
            return themeName
        }
        function getCssClasses(themeName) {
            themeName = themeName || current();
            var result = [],
                themeNameParts = themeName && themeName.split(".");
            if (themeNameParts) {
                result.push("dx-theme-" + themeNameParts[0], "dx-theme-" + themeNameParts[0] + "-typography");
                if (themeNameParts.length > 1)
                    result.push("dx-color-scheme-" + themeNameParts[1])
            }
            return result
        }
        function attachCssClasses(element, themeName) {
            $(element).addClass(getCssClasses(themeName).join(" "))
        }
        function detachCssClasses(element, themeName) {
            $(element).removeClass(getCssClasses(themeName).join(" "))
        }
        $.holdReady(true);
        init({
            _autoInit: true,
            loadCallback: function() {
                $.holdReady(false)
            }
        });
        $(function() {
            if ($(DX_LINK_SELECTOR, context).length)
                throw Error("LINK[rel=dx-theme] tags must go before DevExpress included scripts");
        });
        DX.ui.themes = {
            init: init,
            current: current,
            attachCssClasses: attachCssClasses,
            detachCssClasses: detachCssClasses
        };
        DX.ui.themes.__internals = {
            themeNameFromDevice: themeNameFromDevice,
            waitForThemeLoad: waitForThemeLoad,
            resetTheme: function() {
                $activeThemeLink.attr("href", "about:blank");
                currentThemeName = null;
                pendingThemeName = null
            }
        }
    })(jQuery, DevExpress);
    /*! Module core, file ui.events.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            eventNS = $.event,
            specialNS = eventNS.special,
            EVENT_SOURCES_REGEX = {
                mouse: /(mouse|wheel)/i,
                touch: /^touch/i,
                keyboard: /^key/i,
                pointer: /pointer/i
            };
        var eventSource = function(e) {
                var result = "other";
                $.each(EVENT_SOURCES_REGEX, function(key) {
                    if (this.test(e.type)) {
                        result = key;
                        return false
                    }
                });
                return result
            };
        var isPointerEvent = function(e) {
                return eventSource(e) === "pointer"
            };
        var isMouseEvent = function(e) {
                return eventSource(e) === "mouse" || isPointerEvent(e) && e.pointerType === "mouse"
            };
        var isTouchEvent = function(e) {
                return eventSource(e) === "touch" || isPointerEvent(e) && e.pointerType === "touch"
            };
        var isKeyboardEvent = function(e) {
                return eventSource(e) === "keyboard"
            };
        var addNamespace = function(eventNames, namespace) {
                if (!namespace)
                    throw Error("Namespace is not defined");
                if (typeof eventNames === "string")
                    return addNamespace(eventNames.split(/\s+/g), namespace);
                $.each(eventNames, function(index, eventName) {
                    eventNames[index] = eventName + "." + namespace
                });
                return eventNames.join(" ")
            };
        var eventData = function(e) {
                if (isPointerEvent(e) && isTouchEvent(e)) {
                    var touch = (e.originalEvent.originalEvent || e.originalEvent).changedTouches[0];
                    return {
                            x: touch.pageX,
                            y: touch.pageY,
                            time: e.timeStamp
                        }
                }
                if (isMouseEvent(e))
                    return {
                            x: e.pageX,
                            y: e.pageY,
                            time: e.timeStamp
                        };
                if (isTouchEvent(e)) {
                    var touch = (e.changedTouches || e.originalEvent.changedTouches)[0];
                    return {
                            x: touch.pageX,
                            y: touch.pageY,
                            time: e.timeStamp
                        }
                }
            };
        var eventDelta = function(from, to) {
                return {
                        x: to.x - from.x,
                        y: to.y - from.y,
                        time: to.time - from.time || 1
                    }
            };
        var hasTouches = function(e) {
                if (isTouchEvent(e))
                    return (e.originalEvent.touches || []).length;
                return 0
            };
        var needSkipEvent = function(e) {
                var $target = $(e.target),
                    touchInInput = $target.is("input, textarea, select");
                if (isMouseEvent(e))
                    return touchInInput || e.which > 1;
                if (isTouchEvent(e))
                    return touchInInput && $target.is(":focus") || (e.originalEvent.changedTouches || e.originalEvent.originalEvent.changedTouches).length !== 1
            };
        var createEvent = function(sourceEvent, props) {
                var event = $.Event(sourceEvent),
                    originalEvent = event.originalEvent,
                    propNames = $.event.props.slice();
                if (isMouseEvent(sourceEvent) || isTouchEvent(sourceEvent))
                    $.merge(propNames, $.event.mouseHooks.props);
                if (isKeyboardEvent(sourceEvent))
                    $.merge(propNames, $.event.keyHooks.props);
                if (originalEvent)
                    $.each(propNames, function() {
                        event[this] = originalEvent[this]
                    });
                if (props)
                    $.extend(event, props);
                return event
            };
        var fireEvent = function(props) {
                var event = createEvent(props.originalEvent, props);
                $.event.trigger(event, null, props.target || event.target);
                return event
            };
        var handleGestureEvent = function(e, type) {
                var gestureEvent = $(e.target).data("dxGestureEvent");
                if (!gestureEvent || gestureEvent === type) {
                    $(e.target).data("dxGestureEvent", type);
                    return true
                }
                return false
            };
        var registerEvent = function(eventName, eventObject) {
                var strategy = {};
                if ("noBubble" in eventObject)
                    strategy.noBubble = eventObject.noBubble;
                if ("bindType" in eventObject)
                    strategy.bindType = eventObject.bindType;
                if ("delegateType" in eventObject)
                    strategy.delegateType = eventObject.delegateType;
                $.each(["setup", "teardown", "add", "remove", "trigger", "handle", "_default", "dispose"], function(_, methodName) {
                    if (!eventObject[methodName])
                        return;
                    strategy[methodName] = function() {
                        var args = $.makeArray(arguments);
                        args.unshift(this);
                        return eventObject[methodName].apply(eventObject, args)
                    }
                });
                specialNS[eventName] = strategy
            };
        ui.events = {
            eventSource: eventSource,
            isPointerEvent: isPointerEvent,
            isMouseEvent: isMouseEvent,
            isTouchEvent: isTouchEvent,
            isKeyboardEvent: isKeyboardEvent,
            addNamespace: addNamespace,
            hasTouches: hasTouches,
            eventData: eventData,
            eventDelta: eventDelta,
            needSkipEvent: needSkipEvent,
            createEvent: createEvent,
            fireEvent: fireEvent,
            handleGestureEvent: handleGestureEvent,
            registerEvent: registerEvent
        }
    })(jQuery, DevExpress);
    /*! Module core, file ko.events.js */
    (function($, DX, undefined) {
        if (!DX.support.hasKo)
            return;
        var ko = window.ko,
            events = DX.ui.events;
        var originalRegisterEvent = events.registerEvent;
        var registerKoEvent = function(eventName, eventObject) {
                originalRegisterEvent(eventName, eventObject);
                var koBindingEventName = events.addNamespace(eventName, eventName + "Binding");
                ko.bindingHandlers[eventName] = {update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
                        var $element = $(element),
                            unwrappedValue = ko.utils.unwrapObservable(valueAccessor()),
                            eventSource = unwrappedValue.execute ? unwrappedValue.execute : unwrappedValue;
                        $element.off(koBindingEventName).on(koBindingEventName, $.isPlainObject(unwrappedValue) ? unwrappedValue : {}, function(e) {
                            eventSource(viewModel, e)
                        })
                    }}
            };
        $.extend(events, {registerEvent: registerKoEvent})
    })(jQuery, DevExpress);
    /*! Module core, file ng.events.js */
    (function($, DX, undefined) {
        if (!DX.support.hasNg)
            return;
        var events = DX.ui.events;
        var originalRegisterEvent = events.registerEvent;
        var registerNgEvent = function(eventName, eventObject) {
                originalRegisterEvent(eventName, eventObject);
                var ngEventName = eventName.slice(0, 2) + eventName.charAt(2).toUpperCase() + eventName.slice(3);
                DX.ng.module.directive(ngEventName, ['$parse', function($parse) {
                        return function(scope, element, attr) {
                                var attrValue = $.trim(attr[ngEventName]),
                                    handler,
                                    eventOptions = {};
                                if (attrValue.charAt(0) === "{") {
                                    eventOptions = scope.$eval(attrValue);
                                    handler = $parse(eventOptions.execute)
                                }
                                else
                                    handler = $parse(attr[ngEventName]);
                                element.on(eventName, eventOptions, function(e) {
                                    scope.$apply(function() {
                                        handler(scope, {$event: e})
                                    })
                                })
                            }
                    }])
            };
        $.extend(events, {registerEvent: registerNgEvent})
    })(jQuery, DevExpress);
    /*! Module core, file ui.hierarchicalKeyDownProcessor.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        ui.HierarchicalKeyDownProcessor = DX.Class.inherit({
            _keydown: events.addNamespace("keydown", "HierarchicalKeyDownProcessor"),
            codes: {
                "9": "tab",
                "13": "enter",
                "27": "escape",
                "33": "pageUp",
                "34": "pageDown",
                "37": "leftArrow",
                "38": "upArrow",
                "39": "rightArrow",
                "40": "downArrow",
                "32": "space",
                "70": "F",
                "65": "A"
            },
            ctor: function(options) {
                var _this = this;
                options = options || {};
                if (options.element)
                    this._element = $(options.element);
                this._handler = options.handler;
                this._context = options.context;
                this._childProcessors = [];
                if (this._element)
                    this._element.on(this._keydown, function(e) {
                        _this.process(e)
                    })
            },
            dispose: function() {
                if (this._element)
                    this._element.off(this._keydown);
                this._element = undefined;
                this._handler = undefined;
                this._context = undefined;
                this._childProcessors = undefined
            },
            attachChildProcessor: function() {
                var childProcessor = new ui.HierarchicalKeyDownProcessor;
                this._childProcessors.push(childProcessor);
                return childProcessor
            },
            reinitialize: function(childHandler, childContext) {
                this._context = childContext;
                this._handler = childHandler;
                return this
            },
            process: function(e) {
                var args = {
                        key: this.codes[e.which],
                        ctrl: e.ctrlKey,
                        shift: e.shiftKey,
                        originalEvent: e
                    };
                if (this.codes[e.which] && this._handler && this._handler.call(this._context, args))
                    $.each(this._childProcessors, function(index, childProcessor) {
                        childProcessor.process(e)
                    })
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.dialog.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils;
        var DEFAULT_BUTTON = {
                text: "OK",
                clickAction: function() {
                    return true
                }
            };
        var DX_DIALOG_CLASSNAME = "dx-dialog",
            DX_DIALOG_WRAPPER_CLASSNAME = DX_DIALOG_CLASSNAME + "-wrapper",
            DX_DIALOG_ROOT_CLASSNAME = DX_DIALOG_CLASSNAME + "-root",
            DX_DIALOG_CONTENT_CLASSNAME = DX_DIALOG_CLASSNAME + "-content",
            DX_DIALOG_MESSAGE_CLASSNAME = DX_DIALOG_CLASSNAME + "-message",
            DX_DIALOG_BUTTONS_CLASSNAME = DX_DIALOG_CLASSNAME + "-buttons",
            DX_DIALOG_BUTTON_CLASSNAME = DX_DIALOG_CLASSNAME + "-button";
        var FakeDialogComponent = DX.Component.inherit({
                NAME: "dxDialog",
                ctor: function(element, options) {
                    this.callBase(options)
                },
                _defaultOptionsRules: function() {
                    return this.callBase().slice(0).concat([{
                                device: [{platform: "ios"}, {platform: "ios7"}],
                                options: {width: 276}
                            }, {
                                device: {platform: "android"},
                                options: {
                                    lWidth: "60%",
                                    pWidth: "80%"
                                }
                            }, {
                                device: {
                                    platform: "win8",
                                    phone: false
                                },
                                options: {width: function() {
                                        return $(window).width()
                                    }}
                            }, {
                                device: {
                                    platform: "win8",
                                    phone: true
                                },
                                options: {position: {
                                        my: "top center",
                                        at: "top center",
                                        of: window,
                                        offset: "0 0"
                                    }}
                            }])
                }
            });
        var dialog = function(options) {
                var that = this,
                    result;
                if (!ui.dxPopup)
                    throw new Error("DevExpress.ui.dxPopup required");
                var deferred = $.Deferred();
                var defaultOptions = (new FakeDialogComponent).option();
                options = $.extend(defaultOptions, options);
                var $holder = $(DX.overlayTargetContainer());
                var $element = $("<div>").addClass(DX_DIALOG_CLASSNAME).appendTo($holder);
                var $message = $("<div>").addClass(DX_DIALOG_MESSAGE_CLASSNAME).html(String(options.message));
                var $buttons = $("<div>").addClass(DX_DIALOG_BUTTONS_CLASSNAME);
                var popupInstance = $element.dxPopup({
                        title: options.title || that.title,
                        height: "auto",
                        width: function() {
                            var isPortrait = $(window).height() > $(window).width(),
                                key = (isPortrait ? "p" : "l") + "Width",
                                widthOption = options.hasOwnProperty(key) ? options[key] : options["width"];
                            return $.isFunction(widthOption) ? widthOption() : widthOption
                        },
                        contentReadyAction: function() {
                            popupInstance.content().addClass(DX_DIALOG_CONTENT_CLASSNAME).append($message).append($buttons)
                        },
                        animation: {
                            show: {
                                type: "pop",
                                duration: 400
                            },
                            hide: {
                                type: "pop",
                                duration: 400,
                                to: {
                                    opacity: 0,
                                    scale: 0
                                },
                                from: {
                                    opacity: 1,
                                    scale: 1
                                }
                            }
                        },
                        rtlEnabled: DX.rtlEnabled
                    }).data("dxPopup");
                popupInstance._wrapper().addClass(DX_DIALOG_WRAPPER_CLASSNAME);
                if (options.position)
                    popupInstance.option("position", options.position);
                $.each(options.buttons || [DEFAULT_BUTTON], function() {
                    var button = $("<div>").addClass(DX_DIALOG_BUTTON_CLASSNAME).appendTo($buttons);
                    var action = new DX.Action(this.clickAction, {context: popupInstance});
                    button.dxButton($.extend(this, {clickAction: function() {
                            result = action.execute(arguments);
                            hide()
                        }}))
                });
                popupInstance._wrapper().addClass(DX_DIALOG_ROOT_CLASSNAME);
                function show() {
                    popupInstance.show();
                    utils.resetActiveElement();
                    return deferred.promise()
                }
                function hide(value) {
                    popupInstance.hide().done(function() {
                        popupInstance._element().remove()
                    });
                    deferred.resolve(result || value)
                }
                return {
                        show: show,
                        hide: hide
                    }
            };
        var alert = function(message, title) {
                var dialogInstance,
                    options = $.isPlainObject(message) ? message : {
                        title: title,
                        message: message
                    };
                dialogInstance = ui.dialog.custom(options);
                return dialogInstance.show()
            };
        var confirm = function(message, title) {
                var dialogInstance,
                    options = $.isPlainObject(message) ? message : {
                        title: title,
                        message: message,
                        buttons: [{
                                text: Globalize.localize("Yes"),
                                clickAction: function() {
                                    return true
                                }
                            }, {
                                text: Globalize.localize("No"),
                                clickAction: function() {
                                    return false
                                }
                            }]
                    };
                dialogInstance = ui.dialog.custom(options);
                return dialogInstance.show()
            };
        var notify = function(message, type, displayTime) {
                var options,
                    instance;
                options = $.isPlainObject(message) ? message : {message: message};
                if (!ui.dxToast) {
                    alert(options.message);
                    return
                }
                if (type)
                    options.type = type;
                if (displayTime)
                    options.displayTime = displayTime;
                instance = $("<div>").appendTo(DX.overlayTargetContainer()).addClass("dx-static").dxToast(options).data("dxToast");
                instance.option("hiddenAction", function(args) {
                    args.element.remove();
                    new DX.Action(options.hiddenAction, {context: args.model}).execute(arguments)
                });
                instance.show()
            };
        $.extend(ui, {
            notify: notify,
            dialog: {
                custom: dialog,
                alert: alert,
                confirm: confirm,
                FakeDialogComponent: FakeDialogComponent
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.dataHelper.js */
    (function($, DX, undefined) {
        var data = DX.data;
        var DATA_SOURCE_OPTIONS_METHOD = "_dataSourceOptions",
            DATA_SOURCE_CHANGED_METHOD = "_handleDataSourceChanged",
            DATA_SOURCE_LOAD_ERROR_METHOD = "_handleDataSourceLoadError",
            DATA_SOURCE_LOADING_CHANGED_METHOD = "_handleDataSourceLoadingChanged";
        DX.ui.DataHelperMixin = {
            ctor: function() {
                this.disposing.add(function() {
                    this._disposeDataSource()
                })
            },
            _refreshDataSource: function() {
                this._initDataSource();
                this._loadDataSource()
            },
            _initDataSource: function() {
                var dataSourceOptions = this.option("dataSource"),
                    widgetDataSourceOptions,
                    dataSourceType;
                this._disposeDataSource();
                if (dataSourceOptions) {
                    if (dataSourceOptions instanceof data.DataSource) {
                        this._isSharedDataSource = true;
                        this._dataSource = dataSourceOptions
                    }
                    else {
                        widgetDataSourceOptions = DATA_SOURCE_OPTIONS_METHOD in this ? this[DATA_SOURCE_OPTIONS_METHOD]() : {};
                        dataSourceType = this._dataSourceType ? this._dataSourceType() : data.DataSource;
                        this._dataSource = new dataSourceType($.extend(true, {}, widgetDataSourceOptions, data.utils.normalizeDataSourceOptions(dataSourceOptions)))
                    }
                    this._addDataSourceHandlers()
                }
            },
            _addDataSourceHandlers: function() {
                if (DATA_SOURCE_CHANGED_METHOD in this)
                    this._addDataSourceChangeHandler();
                if (DATA_SOURCE_LOAD_ERROR_METHOD in this)
                    this._addDataSourceLoadErrorHandler();
                if (DATA_SOURCE_LOADING_CHANGED_METHOD in this)
                    this._addDataSourceLoadingChangedHandler()
            },
            _addDataSourceChangeHandler: function() {
                var that = this,
                    dataSource = this._dataSource;
                this._dataSourceChangedHandler = function() {
                    that[DATA_SOURCE_CHANGED_METHOD](dataSource.items())
                };
                dataSource.changed.add(this._dataSourceChangedHandler)
            },
            _addDataSourceLoadErrorHandler: function() {
                this._dataSourceLoadErrorHandler = $.proxy(this[DATA_SOURCE_LOAD_ERROR_METHOD], this);
                this._dataSource.loadError.add(this._dataSourceLoadErrorHandler)
            },
            _addDataSourceLoadingChangedHandler: function() {
                this._dataSourceLoadingChangedHandler = $.proxy(this[DATA_SOURCE_LOADING_CHANGED_METHOD], this);
                this._dataSource.loadingChanged.add(this._dataSourceLoadingChangedHandler)
            },
            _loadDataSource: function() {
                if (this._dataSource) {
                    var dataSource = this._dataSource;
                    if (dataSource.isLoaded())
                        this._dataSourceChangedHandler();
                    else
                        dataSource.load()
                }
            },
            _disposeDataSource: function() {
                if (this._dataSource) {
                    if (this._isSharedDataSource) {
                        delete this._isSharedDataSource;
                        this._dataSource.changed.remove(this._dataSourceChangedHandler);
                        this._dataSource.loadError.remove(this._dataSourceLoadErrorHandler);
                        this._dataSource.loadingChanged.remove(this._dataSourceLoadingChangedHandler)
                    }
                    else
                        this._dataSource.dispose();
                    delete this._dataSource;
                    delete this._dataSourceChangedHandler;
                    delete this._dataSourceLoadErrorHandler;
                    delete this._dataSourceLoadingChangedHandler
                }
            }
        }
    })(jQuery, DevExpress);
    /*! Module core, file ui.events.mspointer.js */
    (function($, DX, undefined) {
        var POINTER_TYPE_MAP = {
                2: "touch",
                3: "pen",
                4: "mouse"
            };
        var pointerEventHook = {
                filter: function(event, originalEvent) {
                    var pointerType = originalEvent.pointerType;
                    if ($.isNumeric(pointerType))
                        event.pointerType = POINTER_TYPE_MAP[pointerType];
                    return event
                },
                props: $.event.mouseHooks.props.concat(["pointerId", "originalTarget", "namespace", "width", "height", "pressure", "result", "tiltX", "charCode", "tiltY", "detail", "isPrimary", "prevValue"])
            };
        $.each(["MSPointerDown", "MSPointerMove", "MSPointerUp", "MSPointerCancel", "MSPointerOver", "MSPointerOut", "MSPointerEnter", "MSPointerLeave", "pointerdown", "pointermove", "pointerup", "pointercancel", "pointerover", "pointerout", "pointerenter", "pointerleave"], function() {
            $.event.fixHooks[this] = pointerEventHook
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.events.touch.js */
    (function($, DX, undefined) {
        var touchEventHook = {
                filter: function(event, originalEvent) {
                    if (originalEvent.changedTouches.length)
                        $.each(["pageX", "pageY", "screenX", "screenY", "clientX", "clientY"], function() {
                            event[this] = originalEvent.changedTouches[0][this]
                        });
                    return event
                },
                props: $.event.mouseHooks.props.concat(["touches", "changedTouches", "targetTouches", "detail", "result", "namespace", "originalTarget", "charCode", "prevValue"])
            };
        $.each(["touchstart", "touchmove", "touchend", "touchcancel"], function() {
            $.event.fixHooks[this] = touchEventHook
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.events.pointer.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            support = DX.support,
            device = $.proxy(DX.devices.real, DX.devices),
            events = ui.events;
        var POINTER_EVENTS_NAMESPACE = "dxPointerEvents",
            MouseStrategyEventMap = {
                dxpointerdown: "mousedown",
                dxpointermove: "mousemove",
                dxpointerup: "mouseup",
                dxpointercancel: ""
            },
            TouchStrategyEventMap = {
                dxpointerdown: "touchstart",
                dxpointermove: "touchmove",
                dxpointerup: "touchend",
                dxpointercancel: "touchcancel"
            },
            PointerStrategyEventMap = {
                dxpointerdown: "pointerdown",
                dxpointermove: "pointermove",
                dxpointerup: "pointerup",
                dxpointercancel: "pointercancel"
            },
            MouseAndTouchStrategyEventMap = {
                dxpointerdown: "touchstart mousedown",
                dxpointermove: "touchmove mousemove",
                dxpointerup: "touchend mouseup",
                dxpointercancel: "touchcancel"
            };
        var eventMap = function() {
                if (support.touch && !(device().tablet || device().phone))
                    return MouseAndTouchStrategyEventMap;
                if (support.touch)
                    return TouchStrategyEventMap;
                return MouseStrategyEventMap
            }();
        var skipTouchWithSameIdentifier = function(pointerEvent) {
                return device().platform === "ios" && (pointerEvent === "dxpointerdown" || pointerEvent === "dxpointerup")
            };
        var SingleEventStrategy = DX.Class.inherit({
                ctor: function(eventName, originalEvents) {
                    this._eventName = eventName;
                    this._eventNamespace = [POINTER_EVENTS_NAMESPACE, ".", this._eventName].join("");
                    this._originalEvents = originalEvents;
                    this._pointerId = 0;
                    this._handlerCount = 0
                },
                _handler: function(e) {
                    if (this._eventName === "dxpointerdown")
                        $(e.target).data("dxGestureEvent", null);
                    if (events.isTouchEvent(e) && skipTouchWithSameIdentifier(this._eventName)) {
                        var touch = e.changedTouches[0];
                        if (this._pointerId === touch.identifier && this._pointerId !== 0)
                            return;
                        this._pointerId = touch.identifier
                    }
                    return events.fireEvent({
                            type: this._eventName,
                            pointerType: events.eventSource(e),
                            originalEvent: e
                        })
                },
                setup: function() {
                    if (this._handlerCount > 0)
                        return;
                    $(document).on(events.addNamespace(this._originalEvents, this._eventNamespace), $.proxy(this._handler, this))
                },
                add: function() {
                    this._handlerCount++
                },
                remove: function() {
                    this._handlerCount--
                },
                teardown: function() {
                    if (this._handlerCount)
                        return;
                    $(document).off("." + this._eventNamespace)
                },
                dispose: function() {
                    $(document).off("." + this._eventNamespace)
                }
            });
        var MultiEventStrategy = SingleEventStrategy.inherit({
                EVENT_LOCK_TIMEOUT: 100,
                _handler: function(e) {
                    if (events.isTouchEvent(e))
                        this._skipNextEvents = true;
                    if (events.isMouseEvent(e) && this._mouseLocked)
                        return;
                    if (events.isMouseEvent(e) && this._skipNextEvents) {
                        this._skipNextEvents = false;
                        this._mouseLocked = true;
                        clearTimeout(this._unlockMouseTimer);
                        this._unlockMouseTimer = setTimeout($.proxy(function() {
                            this._mouseLocked = false
                        }, this), this.EVENT_LOCK_TIMEOUT);
                        return
                    }
                    return this.callBase(e)
                },
                dispose: function() {
                    this.callBase();
                    this._skipNextEvents = false;
                    this._mouseLocked = false;
                    clearTimeout(this._unlockMouseTimer)
                }
            });
        var getStrategy = function() {
                return eventMap === MouseAndTouchStrategyEventMap ? MultiEventStrategy : SingleEventStrategy
            };
        $.each(eventMap, function(pointerEvent, originalEvents) {
            var Strategy = getStrategy();
            events.registerEvent(pointerEvent, new Strategy(pointerEvent, originalEvents))
        });
        DX.ui.events.__internals = DX.ui.events.__internals || {};
        $.extend(DX.ui.events.__internals, {
            SingleEventStrategy: SingleEventStrategy,
            MultiEventStrategy: MultiEventStrategy,
            MouseStrategyEventMap: MouseStrategyEventMap,
            TouchStrategyEventMap: TouchStrategyEventMap,
            PointerStrategyEventMap: PointerStrategyEventMap,
            MouseAndTouchStrategyEventMap: MouseAndTouchStrategyEventMap,
            eventMap: eventMap
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.events.click.js */
    (function($, DX, wnd, undefined) {
        var ua = navigator.userAgent,
            screen = wnd.screen,
            ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            support = DX.support,
            device = $.proxy(DX.devices.real, DX.devices),
            EVENTS_NAME_SPACE = "dxSpecialEvents",
            CLICK_NAME_SPACE = "dxClick" + EVENTS_NAME_SPACE,
            CLICK_EVENT_NAME = "dxclick",
            SCROLLABLE_PARENT_DATA_KEY = "dxClickScrollableParent",
            SCROLLABLE_PARENT_SCROLL_OFFSET_DATA_KEY = "dxClickScrollableParentOffset",
            preferNativeClick = function() {
                var iPhone4SAndElder = device().deviceType === "phone" && screen.height <= 480,
                    iPad2AndElder = device().deviceType === "tablet" && wnd.devicePixelRatio < 2,
                    IOS7AndNewer = device().platform === "ios" && device().version[0] > 6;
                return IOS7AndNewer && (iPhone4SAndElder || iPad2AndElder)
            }(),
            useNativeClick = function() {
                if (!support.touch)
                    return true;
                var chromeInfo = ua.match(/Chrome\/([0-9]+)/) || [],
                    chrome = !!chromeInfo[0],
                    chromeVersion = ~~chromeInfo[1],
                    android = device().platform === "android";
                if (chrome)
                    if (android) {
                        if ($("meta[name=viewport][content*='width=device-width']").length)
                            return false;
                        if (chromeVersion > 31 && wnd.innerWidth <= screen.width)
                            return true;
                        if ($("meta[name=viewport][content*='user-scalable=no']").length)
                            return true
                    }
                    else
                        return true;
                return false
            }();
        var SimulatedStrategy = DX.Class.inherit({
                TOUCH_BOUNDARY: 10,
                ctor: function() {
                    this._startX = 0;
                    this._startY = 0;
                    this._handlerCount = 0;
                    this._target = null
                },
                _touchWasMoved: function(e) {
                    var boundary = this.TOUCH_BOUNDARY;
                    return Math.abs(e.pageX - this._startX) > boundary || Math.abs(e.pageY - this._startY) > boundary
                },
                _getClosestScrollable: function($element) {
                    var $scrollParent = $();
                    if ($element.data(SCROLLABLE_PARENT_DATA_KEY))
                        $scrollParent = $element.data(SCROLLABLE_PARENT_DATA_KEY);
                    else {
                        var $current = $element;
                        while ($current.length) {
                            if ($current[0].scrollHeight - $current[0].offsetHeight > 1) {
                                $scrollParent = $current;
                                $element.data(SCROLLABLE_PARENT_DATA_KEY, $scrollParent);
                                break
                            }
                            $current = $current.parent()
                        }
                    }
                    return $scrollParent
                },
                _saveClosestScrollableOffset: function($element) {
                    var $scrollable = this._getClosestScrollable($element);
                    if ($scrollable.length)
                        $element.data(SCROLLABLE_PARENT_SCROLL_OFFSET_DATA_KEY, $scrollable.scrollTop())
                },
                _closestScrollableWasMoved: function($element) {
                    var $scrollable = $element.data(SCROLLABLE_PARENT_DATA_KEY);
                    return $scrollable && $scrollable.scrollTop() !== $element.data(SCROLLABLE_PARENT_SCROLL_OFFSET_DATA_KEY)
                },
                _hasClosestScrollable: function($element) {
                    var $scrollable = this._getClosestScrollable($element);
                    if (!$scrollable.length)
                        return false;
                    if ($scrollable.is("body"))
                        return false;
                    if ($scrollable === window)
                        return false;
                    if ($scrollable.css("overflow") === "hidden")
                        return false;
                    return true
                },
                _handleStart: function(e) {
                    if (events.isMouseEvent(e) && e.which !== 1)
                        return;
                    this._saveClosestScrollableOffset($(e.target));
                    this._target = e.target;
                    this._startX = e.pageX;
                    this._startY = e.pageY
                },
                _handleEnd: function(e) {
                    var $target = $(e.target);
                    this._nativeClickShouldBeUsed = preferNativeClick && this._hasClosestScrollable($target);
                    if (!$target.is(this._target) || this._touchWasMoved(e) || this._closestScrollableWasMoved($target) || this._nativeClickShouldBeUsed)
                        return;
                    if (!$target.is("input, textarea") && !e.dxPreventBlur)
                        utils.resetActiveElement();
                    if (events.handleGestureEvent(e, CLICK_EVENT_NAME)) {
                        if (!$target.is("input, textarea"))
                            e.preventDefault();
                        events.fireEvent({
                            type: CLICK_EVENT_NAME,
                            originalEvent: e
                        })
                    }
                    this._touchEndTarget = $target;
                    this._reset()
                },
                _handleCancel: function(e) {
                    this._reset()
                },
                _reset: function() {
                    this._target = null
                },
                _handleClick: function(e) {
                    var $target = $(e.target);
                    if ($target.is(this._target) && this._hasClosestScrollable($target))
                        if (events.handleGestureEvent(e, CLICK_EVENT_NAME))
                            events.fireEvent({
                                type: CLICK_EVENT_NAME,
                                originalEvent: e
                            });
                    this._reset()
                },
                _preventFocus: function(e) {
                    if (device().platform === "android" && /^4\.0(\.\d)?/.test(device().version.join(".")))
                        return;
                    e.preventDefault()
                },
                _handleMouseDown: function(e) {
                    if (this._touchEndTarget && !$(e.target).is(this._touchEndTarget)) {
                        this._preventFocus(e);
                        this._touchEndTarget = null
                    }
                },
                _handleElementMouseDown: function(e) {
                    if (!$(e.target).is("input, textarea") && !this._nativeClickShouldBeUsed)
                        this._preventFocus(e)
                },
                _makeElementClickable: function($element) {
                    if (!$element.attr("onclick"))
                        $element.attr("onclick", "void(0)")
                },
                setup: function(element) {
                    var $element = $(element);
                    $element.on(events.addNamespace("mousedown", CLICK_NAME_SPACE), $.proxy(this._handleElementMouseDown, this));
                    this._makeElementClickable($element);
                    if (this._handlerCount > 0)
                        return;
                    var $doc = $(document).on(events.addNamespace("dxpointerdown", CLICK_NAME_SPACE), $.proxy(this._handleStart, this)).on(events.addNamespace("dxpointerup", CLICK_NAME_SPACE), $.proxy(this._handleEnd, this)).on(events.addNamespace("dxpointercancel", CLICK_NAME_SPACE), $.proxy(this._handleCancel, this)).on(events.addNamespace("mousedown", CLICK_NAME_SPACE), $.proxy(this._handleMouseDown, this));
                    if (preferNativeClick)
                        $doc.on(events.addNamespace("click", CLICK_NAME_SPACE), $.proxy(this._handleClick, this))
                },
                add: function() {
                    this._handlerCount++
                },
                remove: function() {
                    this._handlerCount--
                },
                teardown: function(element) {
                    if (this._handlerCount)
                        return;
                    $(element).off("." + CLICK_NAME_SPACE);
                    this.dispose()
                },
                dispose: function() {
                    $(document).off("." + CLICK_NAME_SPACE)
                }
            });
        var NativeStrategy = DX.Class.inherit({
                bindType: "click",
                delegateType: "click",
                handle: function(element, event) {
                    event.type = "dxclick";
                    if (events.handleGestureEvent(event, CLICK_EVENT_NAME))
                        return event.handleObj.handler.call(element, event)
                }
            });
        events.registerEvent(CLICK_EVENT_NAME, new(useNativeClick ? NativeStrategy : SimulatedStrategy));
        DX.ui.events.__internals = DX.ui.events.__internals || {};
        $.extend(DX.ui.events.__internals, {
            NativeClickStrategy: NativeStrategy,
            SimulatedClickStrategy: SimulatedStrategy,
            preferNativeClickAccessor: function(value) {
                if (!arguments.length)
                    return preferNativeClick;
                preferNativeClick = value
            }
        })
    })(jQuery, DevExpress, window);
    /*! Module core, file ui.events.hold.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            jqSpecialEvent = $.event.special,
            EVENTS_NAME_SPACE = "dxSpecialEvents",
            HOLD_NAME_SPACE = "dxHold",
            HOLD_EVENT_NAME = "dxhold",
            HOLD_TIMER_DATA_KEY = EVENTS_NAME_SPACE + "HoldTimer";
        var Hold = DX.Class.inherit({
                HOLD_TIMEOUT: 750,
                TOUCH_BOUNDARY: 5,
                _startX: 0,
                _startY: 0,
                _touchWasMoved: function(e) {
                    var boundary = this.TOUCH_BOUNDARY;
                    return Math.abs(e.pageX - this._startX) > boundary || Math.abs(e.pageY - this._startY) > boundary
                },
                setup: function(element, data) {
                    element = $(element);
                    var handleStart = function(e) {
                            if (element.data(HOLD_TIMER_DATA_KEY))
                                return;
                            this._startX = e.pageX;
                            this._startY = e.pageY;
                            element.data(HOLD_TIMER_DATA_KEY, setTimeout(function() {
                                element.removeData(HOLD_TIMER_DATA_KEY);
                                if (events.handleGestureEvent(e, HOLD_EVENT_NAME))
                                    events.fireEvent({
                                        type: HOLD_EVENT_NAME,
                                        originalEvent: e
                                    })
                            }, data && "timeout" in data ? data.timeout : this.HOLD_TIMEOUT))
                        };
                    var handleMove = function(e) {
                            if (!this._touchWasMoved(e))
                                return;
                            handleEnd()
                        };
                    var handleEnd = function() {
                            clearTimeout(element.data(HOLD_TIMER_DATA_KEY));
                            element.removeData(HOLD_TIMER_DATA_KEY)
                        };
                    element.on(events.addNamespace("dxpointerdown", HOLD_NAME_SPACE), $.proxy(handleStart, this)).on(events.addNamespace("dxpointermove", HOLD_NAME_SPACE), $.proxy(handleMove, this)).on(events.addNamespace("dxpointerup", HOLD_NAME_SPACE), $.proxy(handleEnd, this))
                },
                teardown: function(element) {
                    element = $(element);
                    clearTimeout(element.data(HOLD_TIMER_DATA_KEY));
                    element.removeData(HOLD_TIMER_DATA_KEY).off("." + HOLD_NAME_SPACE)
                }
            });
        events.registerEvent(HOLD_EVENT_NAME, new Hold)
    })(jQuery, DevExpress);
    /*! Module core, file ui.events.wheel.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var EVENT_NAME = "dxmousewheel",
            EVENT_NAMESPACE = "dxWheel";
        var WHEEL_DISTANCE = 10;
        $.event.fixHooks["wheel"] = $.event.mouseHooks;
        var wheelEvent = document.onmousewheel !== undefined ? "mousewheel" : "wheel";
        var wheel = {
                setup: function(element, data) {
                    var $element = $(element);
                    $element.on(events.addNamespace(wheelEvent, EVENT_NAMESPACE), $.proxy(wheel._handleWheel, wheel))
                },
                teardown: function(element) {
                    var $element = $(element);
                    $element.off("." + EVENT_NAMESPACE)
                },
                _handleWheel: function(e) {
                    $(e.target).data("dxGestureEvent", null);
                    var delta = this._getWheelDelta(e.originalEvent);
                    events.fireEvent({
                        type: EVENT_NAME,
                        originalEvent: e,
                        delta: delta
                    });
                    e.stopPropagation()
                },
                _getWheelDelta: function(event) {
                    return event.wheelDelta / 60 || -event.deltaY
                }
            };
        events.registerEvent(EVENT_NAME, wheel)
    })(jQuery, DevExpress);
    /*! Module core, file ui.gestureEmitter.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var GestureEmitter = DX.Class.inherit({
                ctor: function(element) {
                    this._$element = $(element);
                    this._cancelCallback = $.Callbacks()
                },
                getElement: function() {
                    return this._$element
                },
                getDirection: function() {
                    return this.direction
                },
                validate: function(e) {
                    return e.type !== "dxmousewheel"
                },
                configurate: function(data) {
                    $.extend(this, data)
                },
                addCancelCallback: function(callback) {
                    this._cancelCallback.add(callback)
                },
                removeCancelCallback: function() {
                    this._cancelCallback.empty()
                },
                init: $.noop,
                start: $.noop,
                move: $.noop,
                end: $.noop,
                cancel: $.noop,
                wheel: $.noop,
                _fireEvent: function(eventName, event, params) {
                    var eventData = {
                            type: eventName,
                            originalEvent: event,
                            target: this.getElement().get(0)
                        };
                    event = events.fireEvent($.extend(eventData, params));
                    if (event.cancel)
                        this._cancel(event);
                    return event
                },
                _cancel: function(e) {
                    this._cancelCallback.fire()
                }
            });
        var gestureEmitters = [];
        $.extend(ui, {
            GestureEmitter: GestureEmitter,
            gestureEmitters: gestureEmitters
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.scrollEmitter.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var SCROLL_INIT_EVENT = "dxscrollinit",
            SCROLL_START_EVENT = "dxscrollstart",
            SCROLL_MOVE_EVENT = "dxscroll",
            SCROLL_END_EVENT = "dxscrollend",
            SCROLL_STOP_EVENT = "dxscrollstop",
            SCROLL_CANCEL_EVENT = "dxscrollcancel",
            SCROLL_WHEEL_EVENT = "dxscrollwheel",
            INERTIA_TIMEOUT = 100,
            VELOCITY_CALC_TIMEOUT = 200,
            FRAME_DURATION = Math.round(1000 / 60);
        var ScrollEmitter = ui.GestureEmitter.inherit({
                init: function(e) {
                    this._savedEventData = this._prevEventData = events.eventData(e);
                    this._fireEvent(SCROLL_INIT_EVENT, e)
                },
                start: function(e) {
                    this._fireEvent(SCROLL_START_EVENT, e, {delta: events.eventDelta(this._prevEventData, events.eventData(e))})
                },
                move: function(e) {
                    var currentEventData = events.eventData(e);
                    this._fireEvent(SCROLL_MOVE_EVENT, e, {delta: events.eventDelta(this._prevEventData, currentEventData)});
                    var eventDelta = events.eventDelta(this._savedEventData, currentEventData);
                    if (eventDelta.time > VELOCITY_CALC_TIMEOUT)
                        this._savedEventData = this._prevEventData;
                    this._prevEventData = currentEventData
                },
                end: function(e) {
                    var endEventDelta = events.eventDelta(this._prevEventData, events.eventData(e));
                    var velocity = {
                            x: 0,
                            y: 0
                        };
                    if (endEventDelta.time < INERTIA_TIMEOUT) {
                        var deltaEventData = events.eventDelta(this._savedEventData, this._prevEventData);
                        velocity = {
                            x: deltaEventData.x * FRAME_DURATION / deltaEventData.time,
                            y: deltaEventData.y * FRAME_DURATION / deltaEventData.time
                        }
                    }
                    this._fireEvent(SCROLL_END_EVENT, e, {velocity: velocity})
                },
                stop: function(e) {
                    this._fireEvent(SCROLL_STOP_EVENT, e)
                },
                cancel: function(e) {
                    this._fireEvent(SCROLL_CANCEL_EVENT, e)
                },
                wheel: function(e) {
                    this._fireEvent(SCROLL_WHEEL_EVENT, e, {delta: e.delta})
                }
            });
        ui.gestureEmitters.push({
            emitter: ScrollEmitter,
            events: [SCROLL_INIT_EVENT, SCROLL_START_EVENT, SCROLL_MOVE_EVENT, SCROLL_END_EVENT, SCROLL_STOP_EVENT, SCROLL_CANCEL_EVENT, SCROLL_WHEEL_EVENT]
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.swipeEmitter.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            SWIPE_START_EVENT = "dxswipestart",
            SWIPE_EVENT = "dxswipe",
            SWIPE_END_EVENT = "dxswipeend";
        var HorizontalStrategy = {
                defaultItemSizeFunc: function() {
                    return this.getElement().width()
                },
                getBounds: function() {
                    return [this._maxLeftOffset, this._maxRightOffset]
                },
                calcOffsetRatio: function(e) {
                    var endEventData = events.eventData(e);
                    return (endEventData.x - (this._startEventData && this._startEventData.x || 0)) / this._itemSizeFunc().call(this, e)
                },
                isFastSwipe: function(e) {
                    var endEventData = events.eventData(e);
                    return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.x - this._tickData.x) >= endEventData.time - this._tickData.time
                }
            };
        var VerticalStrategy = {
                defaultItemSizeFunc: function() {
                    return this.getElement().height()
                },
                getBounds: function() {
                    return [this._maxTopOffset, this._maxBottomOffset]
                },
                calcOffsetRatio: function(e) {
                    var endEventData = events.eventData(e);
                    return (endEventData.y - (this._startEventData && this._startEventData.y || 0)) / this._itemSizeFunc().call(this, e)
                },
                isFastSwipe: function(e) {
                    var endEventData = events.eventData(e);
                    return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.y - this._tickData.y) >= endEventData.time - this._tickData.time
                }
            };
        var STRATEGIES = {
                horizontal: HorizontalStrategy,
                vertical: VerticalStrategy
            };
        var SwipeEmitter = ui.GestureEmitter.inherit({
                TICK_INTERVAL: 300,
                FAST_SWIPE_SPEED_LIMIT: 5,
                ctor: function(element) {
                    this.callBase(element);
                    this.direction = "horizontal";
                    this.elastic = true
                },
                _getStrategy: function() {
                    return STRATEGIES[this.direction]
                },
                _defaultItemSizeFunc: function() {
                    return this._getStrategy().defaultItemSizeFunc.call(this)
                },
                _itemSizeFunc: function() {
                    return this.itemSizeFunc || this._defaultItemSizeFunc
                },
                init: function(e) {
                    this._startEventData = events.eventData(e);
                    this._tickData = {time: 0}
                },
                start: function(e) {
                    e = this._fireEvent(SWIPE_START_EVENT, e);
                    if (!e.cancel) {
                        this._maxLeftOffset = e.maxLeftOffset;
                        this._maxRightOffset = e.maxRightOffset;
                        this._maxTopOffset = e.maxTopOffset;
                        this._maxBottomOffset = e.maxBottomOffset
                    }
                },
                move: function(e) {
                    var strategy = this._getStrategy(),
                        moveEventData = events.eventData(e),
                        offset = strategy.calcOffsetRatio.call(this, e);
                    offset = this._fitOffset(offset, this.elastic);
                    if (moveEventData.time - this._tickData.time > this.TICK_INTERVAL)
                        this._tickData = moveEventData;
                    this._fireEvent(SWIPE_EVENT, e, {offset: offset});
                    e.preventDefault()
                },
                end: function(e) {
                    var strategy = this._getStrategy(),
                        offsetRatio = strategy.calcOffsetRatio.call(this, e),
                        isFast = strategy.isFastSwipe.call(this, e),
                        startOffset = offsetRatio,
                        targetOffset = this._calcTargetOffset(offsetRatio, isFast);
                    startOffset = this._fitOffset(startOffset, this.elastic);
                    targetOffset = this._fitOffset(targetOffset, false);
                    this._fireEvent(SWIPE_END_EVENT, e, {
                        offset: startOffset,
                        targetOffset: targetOffset
                    })
                },
                _fitOffset: function(offset, elastic) {
                    var strategy = this._getStrategy(),
                        bounds = strategy.getBounds.call(this);
                    if (offset < -bounds[0])
                        return elastic ? (-2 * bounds[0] + offset) / 3 : -bounds[0];
                    if (offset > bounds[1])
                        return elastic ? (2 * bounds[1] + offset) / 3 : bounds[1];
                    return offset
                },
                _calcTargetOffset: function(offsetRatio, isFast) {
                    var result;
                    if (isFast) {
                        result = Math.ceil(Math.abs(offsetRatio));
                        if (offsetRatio < 0)
                            result = -result
                    }
                    else
                        result = Math.round(offsetRatio);
                    return result
                }
            });
        ui.gestureEmitters.push({
            emitter: SwipeEmitter,
            events: [SWIPE_START_EVENT, SWIPE_EVENT, SWIPE_END_EVENT]
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.dragEmitter.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            wrapToArray = utils.wrapToArray;
        var DRAG_START_EVENT = "dxdragstart",
            DRAG_EVENT = "dxdrag",
            DRAG_END_EVENT = "dxdragend",
            DRAG_ENTER_EVENT = "dxdragenter",
            DRAG_LEAVE_EVENT = "dxdragleave",
            DROP_EVENT = "dxdrop";
        var knownDropTargets = [],
            knownDropTargetConfigs = [];
        var dropTargetRegistration = {
                setup: function(element, data) {
                    var knownDropTarget = $.inArray(element, knownDropTargets) !== -1;
                    if (!knownDropTarget) {
                        knownDropTargets.push(element);
                        knownDropTargetConfigs.push(data || {})
                    }
                },
                teardown: function(element, data) {
                    var elementEvents = $._data(element, "events"),
                        handlersCount = 0;
                    $.each([DRAG_ENTER_EVENT, DRAG_LEAVE_EVENT, DROP_EVENT], function(_, eventName) {
                        var eventHandlers = elementEvents[eventName];
                        if (eventHandlers)
                            handlersCount += eventHandlers.length
                    });
                    if (!handlersCount) {
                        var index = $.inArray(element, knownDropTargets);
                        knownDropTargets.splice(index, 1);
                        knownDropTargetConfigs.splice(index, 1)
                    }
                }
            };
        events.registerEvent(DRAG_ENTER_EVENT, dropTargetRegistration);
        events.registerEvent(DRAG_LEAVE_EVENT, dropTargetRegistration);
        events.registerEvent(DROP_EVENT, dropTargetRegistration);
        var getItemConfig = function($element) {
                var dropTargetIndex = $.inArray($element.get(0), knownDropTargets);
                return knownDropTargetConfigs[dropTargetIndex]
            };
        var getItemPosition = function($element) {
                var dropTargetConfig = getItemConfig($element);
                if (dropTargetConfig.itemPositionFunc)
                    return dropTargetConfig.itemPositionFunc();
                else
                    return $element.offset()
            };
        var getItemSize = function($element) {
                var dropTargetConfig = getItemConfig($element);
                if (dropTargetConfig.itemSizeFunc)
                    return dropTargetConfig.itemSizeFunc();
                else
                    return {
                            width: $element.width(),
                            height: $element.height()
                        }
            };
        var DragEmitter = ui.GestureEmitter.inherit({
                ctor: function(element) {
                    this.callBase(element);
                    this.direction = "both"
                },
                init: function(e) {
                    var eventData = events.eventData(e);
                    this._startEventData = eventData
                },
                start: function(e) {
                    e = this._fireEvent(DRAG_START_EVENT, e);
                    this._maxLeftOffset = e.maxLeftOffset;
                    this._maxRightOffset = e.maxRightOffset;
                    this._maxTopOffset = e.maxTopOffset;
                    this._maxBottomOffset = e.maxBottomOffset;
                    var dropTargets = wrapToArray(e.targetElements || knownDropTargets);
                    this._$dropTargetElements = $.map(dropTargets, function(element) {
                        return $(element)
                    })
                },
                move: function(e) {
                    var eventData = events.eventData(e),
                        dragOffset = this._calculateOffset(eventData);
                    this._fireEvent(DRAG_EVENT, e, {offset: dragOffset});
                    this._processDropTargets(e, dragOffset);
                    e.preventDefault()
                },
                _calculateOffset: function(eventData) {
                    return {
                            x: this._calculateXOffset(eventData),
                            y: this._calculateYOffset(eventData)
                        }
                },
                _calculateXOffset: function(eventData) {
                    if (this.direction !== "vertical") {
                        var offset = eventData.x - this._startEventData.x;
                        return this._fitOffset(offset, this._maxLeftOffset, this._maxRightOffset)
                    }
                    return 0
                },
                _calculateYOffset: function(eventData) {
                    if (this.direction !== "horizontal") {
                        var offset = eventData.y - this._startEventData.y;
                        return this._fitOffset(offset, this._maxTopOffset, this._maxBottomOffset)
                    }
                    return 0
                },
                _fitOffset: function(offset, minOffset, maxOffset) {
                    if (minOffset != null)
                        offset = Math.max(offset, -minOffset);
                    if (maxOffset != null)
                        offset = Math.min(offset, maxOffset);
                    return offset
                },
                _processDropTargets: function(e, dragOffset) {
                    var target = this._findDropTarget(e),
                        sameTarget = target === this._$currentDropTarget;
                    if (!sameTarget) {
                        this._fireDropTargetEvent(e, DRAG_LEAVE_EVENT);
                        this._$currentDropTarget = target;
                        this._fireDropTargetEvent(e, DRAG_ENTER_EVENT)
                    }
                },
                _fireDropTargetEvent: function(event, eventName) {
                    if (!this._$currentDropTarget)
                        return;
                    var eventData = {
                            type: eventName,
                            originalEvent: event,
                            draggingElement: this._$element.get(0),
                            target: this._$currentDropTarget.get(0)
                        };
                    events.fireEvent(eventData)
                },
                _findDropTarget: function(e) {
                    var that = this,
                        $result;
                    $.each(this._$dropTargetElements, function(_, $target) {
                        if (that._checkDropTarget($target, e)) {
                            $result = $target;
                            return false
                        }
                    });
                    return $result
                },
                _checkDropTarget: function($target, e) {
                    var isDraggingElement = $target.get(0) === this._$element.get(0);
                    if (isDraggingElement)
                        return false;
                    var targetPosition = getItemPosition($target);
                    if (e.pageX < targetPosition.left)
                        return false;
                    if (e.pageY < targetPosition.top)
                        return false;
                    var targetSize = getItemSize($target);
                    if (e.pageX > targetPosition.left + targetSize.width)
                        return false;
                    if (e.pageY > targetPosition.top + targetSize.height)
                        return false;
                    return $target
                },
                end: function(e) {
                    var eventData = events.eventData(e);
                    this._fireEvent(DRAG_END_EVENT, e, {offset: this._calculateOffset(eventData)});
                    this._fireDropTargetEvent(e, DROP_EVENT);
                    delete this._$currentDropTarget
                }
            });
        ui.gestureEmitters.push({
            emitter: DragEmitter,
            events: [DRAG_START_EVENT, DRAG_EVENT, DRAG_END_EVENT]
        });
        DX.ui.events.__internals = DX.ui.events.__internals || {};
        $.extend(DX.ui.events.__internals, {dropTargets: knownDropTargets})
    })(jQuery, DevExpress);
    /*! Module core, file ui.events.gesture.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils;
        var abs = Math.abs;
        var GESTURE_EVENT = "dxGesture",
            GESTURE_EVENT_DATA = "dxGestureEmitter",
            GESTURE_LOCK_KEY = "dxGestureLock",
            GESTURE_UNLOCK_TIMEOUT = 400,
            TOUCH_BOUNDARY = 10,
            HORIZONTAL = "horizontal",
            VERTICAL = "vertical",
            BOTH = "both";
        var GestureEventManager = DX.Class.inherit({
                SLEEP: 0,
                INITED: 1,
                STARTED: 2,
                ctor: function() {
                    this._attachHandlers();
                    this.reset()
                },
                _attachHandlers: function() {
                    $(document).on(events.addNamespace("dxpointerdown", GESTURE_EVENT), $.proxy(this._handlePointerDown, this)).on(events.addNamespace("dxpointermove", GESTURE_EVENT), $.proxy(this._handlePointerMove, this)).on(events.addNamespace("dxpointerup dxpointercancel", GESTURE_EVENT), $.proxy(this._handlePointerUp, this)).on(events.addNamespace("dxmousewheel", GESTURE_EVENT), $.proxy(this._handleMouseWheel, this))
                },
                _eachEmitter: function(callback) {
                    $.each(this._activeEmitters || {}, function(direction, emitter) {
                        return callback(emitter, direction)
                    })
                },
                _noEmitters: function() {
                    return $.isEmptyObject(this._activeEmitters)
                },
                reset: function() {
                    this._eachEmitter(function(emitter) {
                        emitter.removeCancelCallback()
                    });
                    this._forgetGesture();
                    this._stage = this.SLEEP;
                    this._activeEmitters = {}
                },
                _handlePointerDown: function(e) {
                    if (events.needSkipEvent(e) || events.hasTouches(e) > 1)
                        return;
                    this.reset();
                    this._activeEmitters = this._closestEmitter(e);
                    if (this._noEmitters())
                        return;
                    this._startEvent = e;
                    this._startEventData = events.eventData(e);
                    this._stage = this.INITED;
                    this._applyToActive("init", e)
                },
                _applyToActive: function(method) {
                    var args = $.makeArray(arguments).slice(1);
                    this._eachEmitter(function(emitter) {
                        if (method in emitter)
                            emitter[method].apply(emitter, args)
                    })
                },
                _closestEmitter: function(e) {
                    var result = {},
                        foundForAllDirections = false,
                        $element = $(e.target);
                    while ($element.length && !foundForAllDirections) {
                        var emitter = $element.data(GESTURE_EVENT_DATA);
                        if (emitter && emitter.validate(e)) {
                            var direction = emitter.getDirection(e);
                            emitter.addCancelCallback($.proxy(this._handleCancel, this, emitter, e));
                            result[direction] = result[direction] || emitter
                        }
                        foundForAllDirections = result[HORIZONTAL] && result[VERTICAL] || result[BOTH];
                        $element = $element.parent()
                    }
                    return result
                },
                _handleCancel: function(canceledEmitter, e) {
                    var canceledDirection;
                    this._eachEmitter(function(emitter, direction) {
                        if (emitter === canceledEmitter) {
                            canceledDirection = direction;
                            emitter.removeCancelCallback()
                        }
                    });
                    this._forgetGesture([canceledEmitter]);
                    this._cancelEmitter(canceledEmitter, e);
                    if (this._noEmitters())
                        this.reset()
                },
                _handlePointerMove: function(e) {
                    if (this._stage === this.INITED)
                        this._handleStart(e);
                    if (this._stage === this.STARTED)
                        this._handleMove(e)
                },
                _handleStart: function(e) {
                    this._filterEmitters(e);
                    if (this._noEmitters())
                        return;
                    this._resetActiveElement();
                    this._applyToActive("start", this._startEvent);
                    this._stage = this.STARTED
                },
                _resetActiveElement: function() {
                    if (DX.devices.real().platform !== "ios")
                        return;
                    this._eachEmitter(function(emitter) {
                        if ($(":focus", emitter.getElement()).length)
                            utils.resetActiveElement()
                    })
                },
                _filterEmitters: function(e) {
                    this._filterByDirection(e);
                    if (this._emitersAmount() > 1)
                        this._takeFirstEmitter()
                },
                _emitersAmount: function() {
                    var result = 0;
                    this._eachEmitter(function() {
                        result++
                    });
                    return result
                },
                _filterByDirection: function(e) {
                    var delta = events.eventDelta(this._startEventData, events.eventData(e)),
                        horizontalMove = abs(delta.y) < abs(delta.x),
                        verticalMove = abs(delta.y) > abs(delta.x),
                        horizontalEmmiter = this._activeEmitters[HORIZONTAL],
                        verticalEmmiter = this._activeEmitters[VERTICAL],
                        bothEmitter = this._activeEmitters[BOTH],
                        existsHorizontalEmitter = horizontalEmmiter || bothEmitter,
                        existsVerticalEmitter = verticalEmmiter || bothEmitter;
                    if (horizontalMove && existsHorizontalEmitter)
                        this._cancelEmitter(verticalEmmiter, e);
                    else if (verticalMove && existsVerticalEmitter)
                        this._cancelEmitter(horizontalEmmiter, e)
                },
                _cancelEmitter: function(canceledEmmiter, e) {
                    if (!canceledEmmiter)
                        return;
                    canceledEmmiter.cancel(e);
                    delete this._activeEmitters[canceledEmmiter.getDirection(e)]
                },
                _takeFirstEmitter: function() {
                    var activeEmitters = {};
                    this._eachEmitter(function(emitter, direction) {
                        activeEmitters[direction] = emitter;
                        return false
                    });
                    this._activeEmitters = activeEmitters
                },
                _prepareGesture: function() {
                    this._gestureLocked = true;
                    clearTimeout(this._gestureEndTimer);
                    this._eachEmitter(function(emitter) {
                        emitter.getElement().data(GESTURE_LOCK_KEY, true)
                    });
                    ui.feedback.reset()
                },
                _handleMove: function(e) {
                    if (!this._gestureLocked) {
                        var delta = events.eventDelta(this._startEventData, events.eventData(e));
                        if (abs(delta.x) > TOUCH_BOUNDARY || abs(delta.y) > TOUCH_BOUNDARY) {
                            events.handleGestureEvent(e, GESTURE_EVENT);
                            this._prepareGesture()
                        }
                    }
                    this._applyToActive("move", e)
                },
                _forgetGesture: function(activeEmitters) {
                    activeEmitters = activeEmitters || this._activeEmitters;
                    if (this._noEmitters())
                        return;
                    this._gestureLocked = false;
                    this._gestureEndTimer = setTimeout(function() {
                        $.each(activeEmitters, function(_, emitter) {
                            emitter.getElement().data(GESTURE_LOCK_KEY, false)
                        })
                    }, GESTURE_UNLOCK_TIMEOUT)
                },
                _handlePointerUp: function(e) {
                    if (!DX.devices.isRippleEmulator() && events.hasTouches(e))
                        return;
                    if (this._stage === this.STARTED)
                        this._applyToActive("end", e);
                    else if (this._stage === this.INITED)
                        this._applyToActive("stop", e);
                    this.reset()
                },
                _handleMouseWheel: function(e) {
                    this._handlePointerDown(e);
                    if (this._stage !== this.INITED)
                        return;
                    this._takeFirstEmitter();
                    this._eachEmitter(function(emitter, direction) {
                        var prop = direction !== "horizontal" ? "pageY" : "pageX";
                        e[prop] += e.delta
                    });
                    this._handlePointerMove(e);
                    this._handlePointerUp(e)
                },
                isActive: function(element) {
                    var result = false;
                    this._eachEmitter(function(emitter) {
                        result = result || emitter.getElement().is(element)
                    });
                    return result
                }
            });
        var gestureEventManager = new GestureEventManager;
        $.each(ui.gestureEmitters, function(_, emitterConfig) {
            var emitterClass = emitterConfig.emitter;
            $.each(emitterConfig.events, function(_, eventName) {
                events.registerEvent(eventName, {
                    noBubble: true,
                    setup: function(element, data) {
                        var emitter = $(element).data(GESTURE_EVENT_DATA) || new emitterClass(element);
                        emitter.configurate(data);
                        $(element).data(GESTURE_EVENT_DATA, emitter)
                    },
                    teardown: function(element) {
                        if (gestureEventManager.isActive(element))
                            gestureEventManager.reset();
                        $(element).removeData(GESTURE_EVENT_DATA)
                    }
                })
            })
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.widget.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            UI_FEEDBACK = "UIFeedback",
            UI_FEEDBACK_CLASS = "dx-feedback",
            ACTIVE_STATE_CLASS = "dx-state-active",
            DISABLED_STATE_CLASS = "dx-state-disabled",
            INVISIBLE_STATE_CLASS = "dx-state-invisible",
            HOVERED_STATE_CLASS = "dx-state-hover-enabled",
            FEEDBACK_SHOW_TIMEOUT = 30,
            FEEDBACK_HIDE_TIMEOUT = 400,
            ANONYMOUS_TEMPLATE_NAME = "template",
            TEMPLATE_SELECTOR = "[data-options*='dxTemplate']",
            TEMPLATES_DATA_KEY = "dxTemplates";
        var getTemplateOptions = function(element) {
                var options = $(element).data("options");
                if ($.trim(options).charAt(0) !== "{")
                    options = "{" + options + "}";
                return new Function("return " + options)().dxTemplate
            };
        var activeElement,
            events = ui.events;
        ui.feedback = {reset: function() {
                handleEnd(true)
            }};
        ui.Widget = DX.DOMComponent.inherit({
            NAME: "Widget",
            NAMESPACE: ui,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    disabled: false,
                    visible: true,
                    activeStateEnabled: true,
                    width: undefined,
                    height: undefined,
                    contentReadyAction: null,
                    hoverStateEnabled: true
                })
            },
            _init: function() {
                this.callBase();
                this._feedbackShowTimeout = FEEDBACK_SHOW_TIMEOUT;
                this._feedbackHideTimeout = FEEDBACK_HIDE_TIMEOUT;
                if (this._templatesSupported()) {
                    this._initTemplates();
                    this._initContentReadyAction()
                }
            },
            _templatesSupported: function() {
                return this._renderContentImpl !== DX.abstract
            },
            _initTemplates: function() {
                var that = this,
                    templates = {},
                    dataTemplateElements = this._element().data(TEMPLATES_DATA_KEY),
                    templateElements = dataTemplateElements ? dataTemplateElements : this._element().contents().filter(TEMPLATE_SELECTOR);
                this._templateProvider = new ui.TemplateProvider;
                this._templateClass = this._templateProvider.getTemplateClass(this);
                if (templateElements.length) {
                    var templatesMap = {};
                    templateElements.each(function() {
                        var templateOptions = getTemplateOptions(this);
                        if (!templateOptions)
                            return;
                        if (!templateOptions.name)
                            throw Error("Template name was not specified");
                        templatesMap[templateOptions.name] = templatesMap[templateOptions.name] || [];
                        templatesMap[templateOptions.name].push(this)
                    });
                    $.each(templatesMap, function(templateName, value) {
                        var deviceTemplate = that._findTemplateByDevice(value);
                        if (deviceTemplate)
                            templates[templateName] = that._createTemplate(deviceTemplate)
                    })
                }
                else
                    templates[ANONYMOUS_TEMPLATE_NAME] = that._createTemplate(that._element().contents());
                this._templates = templates
            },
            _getTemplateByOption: function(optionName) {
                return this._getTemplate(this.option(optionName))
            },
            _getTemplate: function(templateName) {
                var result = this._acquireTemplate.apply(this, arguments);
                if (!result && this._templateProvider.supportDefaultTemplate(this)) {
                    result = this._templateProvider.getDefaultTemplate(this);
                    if (!result)
                        throw Error(DX.utils.stringFormat("Template \"{0}\" was not found and no default template specified!", templateName));
                }
                return result
            },
            _acquireTemplate: function(templateSource) {
                if (templateSource == null)
                    return templateSource;
                if (templateSource instanceof this._templateClass)
                    return templateSource;
                if (templateSource.nodeType || templateSource.jquery) {
                    templateSource = $(templateSource);
                    if (templateSource.is("script"))
                        templateSource = templateSource.html();
                    return this._createTemplate(templateSource)
                }
                if (typeof templateSource === "string")
                    return this._templates[templateSource];
                if ($.isFunction(templateSource)) {
                    var args = $.makeArray(arguments).slice(1);
                    return this._acquireTemplate(templateSource.apply(this, args))
                }
                return this._acquireTemplate(templateSource.toString())
            },
            _createTemplate: function(element) {
                return new this._templateClass(element)
            },
            _findTemplateByDevice: function(templates) {
                var suitableTemplate = DX.utils.findBestMatches(DX.devices.current(), templates, function(template) {
                        return getTemplateOptions(template)
                    })[0];
                $.each(templates, function(index, template) {
                    if (template !== suitableTemplate)
                        $(template).remove()
                });
                return suitableTemplate
            },
            _cleanTemplates: function() {
                $.each(this._templates, function(templateName, template) {
                    template.dispose()
                })
            },
            _initContentReadyAction: function() {
                this._contentReadyAction = this._createActionByOption("contentReadyAction", {excludeValidators: ["gesture", "designMode", "disabled"]})
            },
            _render: function() {
                this.callBase();
                this._element().addClass("dx-widget");
                this._toggleDisabledState(this.option("disabled"));
                this._toggleVisibility(this.option("visible"));
                this._refreshFeedback();
                this._renderDimensions();
                if (this._templatesSupported())
                    this._renderContent()
            },
            _renderContent: function() {
                this._renderContentImpl();
                this._fireContentReadyAction()
            },
            _renderContentImpl: DX.abstract,
            _fireContentReadyAction: function() {
                this._contentReadyAction({excludeValidators: ["disabled", "gesture"]})
            },
            _dispose: function() {
                if (this._templatesSupported())
                    this._cleanTemplates();
                this._contentReadyAction = null;
                this._clearTimers();
                if (activeElement && activeElement.closest(this._element()).length)
                    activeElement = null;
                this.callBase()
            },
            _clean: function() {
                this.callBase();
                this._element().empty()
            },
            _clearTimers: function() {
                clearTimeout(this._feedbackHideTimer);
                clearTimeout(this._feedbackShowTimer)
            },
            _toggleVisibility: function(visible) {
                this._element().toggleClass(INVISIBLE_STATE_CLASS, !visible)
            },
            _toggleHoverStateRequest: function(value) {
                if (this.option("hoverStateEnabled"))
                    this._toggleHoverState(value)
            },
            _toggleHoverState: function(value) {
                this._element().toggleClass(HOVERED_STATE_CLASS, value)
            },
            _renderDimensions: function() {
                var width = this.option("width"),
                    height = this.option("height");
                this._setDimension(width, "width");
                this._setDimension(height, "height")
            },
            _setDimension: function(dimensionSize, dimension) {
                var $element = this._element();
                dimensionSize = $.isFunction(dimensionSize) ? dimensionSize() : dimensionSize;
                if ($.isNumeric(dimensionSize))
                    dimensionSize = dimensionSize + "px";
                if (!dimensionSize && dimension === "width")
                    dimensionSize = this._calculateWidth();
                $element.css(dimension, dimensionSize)
            },
            _calculateWidth: function() {
                var $element = this._element(),
                    explicitWidth = $element[0].style.width,
                    calculatedWidth;
                if (explicitWidth[explicitWidth.length - 1] === "%" && !this.option("width"))
                    return explicitWidth;
                else
                    calculatedWidth = explicitWidth && explicitWidth !== "auto" && explicitWidth !== "inherit" ? $element.outerWidth() : this.option("width");
                return calculatedWidth
            },
            _refreshFeedback: function() {
                if (this._feedbackDisabled()) {
                    this._feedbackOff(true);
                    this._element().removeClass(UI_FEEDBACK_CLASS)
                }
                else
                    this._element().addClass(UI_FEEDBACK_CLASS)
            },
            _feedbackDisabled: function() {
                return !this.option("activeStateEnabled") || this.option("disabled")
            },
            _feedbackOn: function(element, immediate) {
                if (this._feedbackDisabled())
                    return;
                this._clearTimers();
                if (immediate)
                    this._feedbackShow(element);
                else
                    this._feedbackShowTimer = window.setTimeout($.proxy(this._feedbackShow, this, element), this._feedbackShowTimeout);
                this._saveActiveElement()
            },
            _feedbackShow: function(element) {
                var activeStateElement = this._element();
                if (this._activeStateUnit)
                    activeStateElement = $(element).closest(this._activeStateUnit);
                if (!activeStateElement.hasClass(DISABLED_STATE_CLASS)) {
                    activeStateElement.addClass(ACTIVE_STATE_CLASS);
                    this._toggleHoverStateRequest(false)
                }
            },
            _saveActiveElement: function() {
                activeElement = this._element()
            },
            _feedbackOff: function(immediate) {
                this._clearTimers();
                if (immediate)
                    this._feedbackHide();
                else
                    this._feedbackHideTimer = window.setTimeout($.proxy(this._feedbackHide, this), this._feedbackHideTimeout)
            },
            _feedbackHide: function() {
                var activeStateElement = this._element();
                if (this._activeStateUnit)
                    activeStateElement = activeStateElement.find(this._activeStateUnit);
                activeStateElement.removeClass(ACTIVE_STATE_CLASS);
                this._toggleHoverStateRequest(!this.option("disabled"));
                this._clearActiveElement()
            },
            _clearActiveElement: function() {
                var rootDomElement = this._element().get(0),
                    activeDomElement = activeElement && activeElement.get(0);
                if (activeDomElement && (activeDomElement === rootDomElement || $.contains(rootDomElement, activeDomElement)))
                    activeElement = null
            },
            _toggleDisabledState: function(value) {
                this._element().toggleClass(DISABLED_STATE_CLASS, Boolean(value));
                this._toggleHoverStateRequest(!value)
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"disabled":
                        this._toggleDisabledState(value);
                        this._refreshFeedback();
                        break;
                    case"activeStateEnabled":
                        this._refreshFeedback();
                        break;
                    case"hoverStateEnabled":
                        this._toggleHoverState(value);
                        break;
                    case"visible":
                        this._toggleVisibility(value);
                        break;
                    case"width":
                    case"height":
                        this._renderDimensions();
                        break;
                    case"contentReadyAction":
                        this._initContentReadyAction();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            repaint: function() {
                this._refresh()
            }
        });
        var handleStart = function(args, immediate) {
                var e = args.jQueryEvent,
                    $target = args.element;
                if (events.needSkipEvent(e))
                    return;
                if (activeElement)
                    getWidget(activeElement)._feedbackOff(true);
                var closestFeedbackElement = $target.closest("." + UI_FEEDBACK_CLASS),
                    widget;
                if (closestFeedbackElement.length) {
                    widget = getWidget(closestFeedbackElement);
                    widget._feedbackOn($target, immediate);
                    if (immediate)
                        widget._feedbackOff()
                }
            };
        var handleEnd = function(immediate) {
                if (!activeElement)
                    return;
                getWidget(activeElement)._feedbackOff(immediate)
            };
        var getWidget = function(widgetElement) {
                var result;
                $.each(widgetElement.data("dxComponents"), function(index, componentName) {
                    if (ui[componentName] && ui[componentName].subclassOf(ui.Widget)) {
                        result = widgetElement.data(componentName);
                        return false
                    }
                });
                return result
            };
        $(function() {
            var startAction = new DX.Action(handleStart);
            $(document).on(events.addNamespace("dxpointerdown", UI_FEEDBACK), function(e) {
                startAction.execute({
                    jQueryEvent: e,
                    element: $(e.target)
                })
            }).on(events.addNamespace("dxpointerup dxpointercancel", UI_FEEDBACK), function(e) {
                var activeElementClicked = activeElement && $(e.target).closest("." + UI_FEEDBACK_CLASS).get(0) === activeElement.get(0);
                if (activeElementClicked)
                    startAction.execute({
                        jQueryEvent: e,
                        element: $(e.target)
                    }, true);
                handleEnd()
            })
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.editor.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        DX.registerComponent("dxEditor", ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    value: undefined,
                    valueChangeAction: undefined
                })
            },
            _recreateValueChangeAction: function() {
                this._valueChangeAction = this._createActionByOption("valueChangeAction")
            },
            _suppressValueChangeAction: function() {
                this._valueChangeActionSuppressed = true
            },
            _resumeValueChangeAction: function() {
                this._valueChangeActionSuppressed = false
            },
            _render: function() {
                this._recreateValueChangeAction();
                this.callBase()
            },
            _raiseValueChangeAction: function(value, previousValue, extraArguments) {
                var args = {
                        value: value,
                        previousValue: previousValue,
                        jQueryEvent: this._valueChangeEventInstance
                    };
                if (extraArguments)
                    args = $.extend(args, extraArguments);
                this._valueChangeAction(args)
            },
            _optionChanged: function(name, value, previousValue) {
                switch (name) {
                    case"valueChangeAction":
                        this._recreateValueChangeAction();
                        break;
                    case"value":
                        if (!this._valueChangeActionSuppressed)
                            this._raiseValueChangeAction(value, previousValue);
                        this._valueChangeEventInstance = undefined;
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module core, file ui.template.js */
    (function($, DX, undefined) {
        var isString = DX.utils.isString;
        var currentTemplateEngine;
        var templateEngines = [];
        var BaseTemplate = DevExpress.Class.inherit({
                _compile: function(html, element) {
                    return element
                },
                _render: function(template, data) {
                    return template
                },
                ctor: function(element) {
                    this._element = $(element);
                    if (this._element.length === 1) {
                        if (this._element[0].nodeName.toLowerCase() !== "script")
                            this._element = $("<div />").append(this._element);
                        this._template = this._compile(this._element.html() || "", this._element)
                    }
                },
                render: function(container, data) {
                    var result;
                    if (this._template) {
                        result = this._render(this._template, data);
                        if (isString(result))
                            result = $.parseHTML(result);
                        result = $(result);
                        if (container)
                            container.append(result);
                        return result
                    }
                },
                dispose: $.noop
            });
        var createTemplateEngine = function(options) {
                if (options && options.compile && options.render)
                    return BaseTemplate.inherit({
                            allowRenderToDetachedContainer: options.allowRenderToDetachedContainer !== false,
                            _compile: options.compile,
                            _render: options.render
                        });
                else
                    throw Error("Template Engine must contains compile and render methods");
            };
        if (window.ko) {
            var koCustomTemplateEngine = function(){};
            koCustomTemplateEngine.prototype = ko.utils.extend(new ko.templateEngine, {
                renderTemplateSource: function(templateSource, bindingContext, options) {
                    var precompiledTemplate = templateSource["data"]("precompiledTemplate");
                    if (!precompiledTemplate) {
                        precompiledTemplate = new currentTemplateEngine(templateSource.domElement);
                        templateSource["data"]("precompiledTemplate", precompiledTemplate)
                    }
                    return precompiledTemplate.render(null, bindingContext.$data)
                },
                allowTemplateRewriting: false
            })
        }
        DevExpress.ui.setTemplateEngine = function(templateEngine) {
            if (isString(templateEngine)) {
                currentTemplateEngine = templateEngines && templateEngines[templateEngine];
                if (!currentTemplateEngine && templateEngine !== "default")
                    throw Error(DX.utils.stringFormat("Template Engine \"{0}\" is not supported", templateEngine));
            }
            else
                currentTemplateEngine = createTemplateEngine(templateEngine) || currentTemplateEngine;
            if (window.ko)
                ko.setTemplateEngine(currentTemplateEngine ? new koCustomTemplateEngine : new ko.nativeTemplateEngine)
        };
        DevExpress.ui.TemplateProvider = DevExpress.ui.TemplateProvider.inherit({getTemplateClass: function() {
                if (currentTemplateEngine)
                    return currentTemplateEngine;
                return this.callBase.apply(this, arguments)
            }});
        var registerTemplateEngine = function(name, templateOptions) {
                templateEngines[name] = createTemplateEngine(templateOptions)
            };
        registerTemplateEngine("jquery-tmpl", {
            compile: function(html, element) {
                return element
            },
            render: function(template, data) {
                return template.tmpl(data)
            }
        });
        registerTemplateEngine("jsrender", {
            compile: function(html) {
                return $.templates(html)
            },
            render: function(template, data) {
                return template.render(data)
            }
        });
        registerTemplateEngine("mustache", {
            compile: function(html) {
                return Mustache.compile(html)
            },
            render: function(template, data) {
                return template(data)
            }
        });
        registerTemplateEngine("hogan", {
            compile: function(html) {
                return Hogan.compile(html)
            },
            render: function(template, data) {
                return template.render(data)
            }
        });
        registerTemplateEngine("underscore", {
            compile: function(html) {
                return _.template(html)
            },
            render: function(template, data) {
                return template(data)
            }
        });
        registerTemplateEngine("handlebars", {
            compile: function(html) {
                return Handlebars.compile(html)
            },
            render: function(template, data) {
                return template(data)
            }
        });
        registerTemplateEngine("doT", {
            compile: function(html) {
                return doT.template(html)
            },
            render: function(template, data) {
                return template(data)
            }
        })
    })(jQuery, DevExpress);
    /*! Module core, file ui.collectionContainerWidget.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var CollectionContainerWidget = ui.Widget.inherit({
                _setDefaultOptions: function() {
                    this.callBase();
                    this.option({
                        items: [],
                        itemTemplate: "item",
                        itemRender: null,
                        itemRenderedAction: null,
                        itemClickAction: null,
                        itemHoldAction: null,
                        itemHoldTimeout: 750,
                        noDataText: Globalize.localize("dxCollectionContainerWidget-noDataText"),
                        dataSource: null,
                        selectedIndex: -1,
                        itemSelectAction: null
                    })
                },
                _init: function() {
                    this.callBase();
                    this._cleanRenderedItems();
                    this._refreshDataSource()
                },
                _dataSourceOptions: function() {
                    var options = {
                            paginate: false,
                            _preferSync: false
                        };
                    if ($.isArray(this.option("dataSource")))
                        options._preferSync = true;
                    return options
                },
                _cleanRenderedItems: function() {
                    this._renderedItemsCount = 0
                },
                _fireSelectItemEvent: function(index, prevIndex) {
                    if (this._selectionEnabled()) {
                        this._updateSelectedIndex(index, prevIndex);
                        this._handleItemEvent(this._selectedItemElement(index), "itemSelectAction", {
                            selectedIndex: index,
                            previousIndex: prevIndex
                        }, {excludeValidators: ["gesture", "disabled"]})
                    }
                },
                _optionChanged: function(name, value, prevValue) {
                    switch (name) {
                        case"items":
                            if (this._selectionEnabled()) {
                                var itemsCount = value && value.length || 0,
                                    maxIndex = Math.max(itemsCount - 1, 0);
                                if (maxIndex < this.option("selectedIndex"))
                                    this.option("selectedIndex", 0)
                            }
                            this._cleanRenderedItems();
                            this._invalidate();
                            break;
                        case"dataSource":
                            this._refreshDataSource();
                            if (!this._dataSource)
                                this.option("items", []);
                            this._renderEmptyMessage();
                            break;
                        case"noDataText":
                            this._renderEmptyMessage();
                            break;
                        case"itemTemplate":
                            this._invalidate();
                            break;
                        case"itemRender":
                            this._itemRender = null;
                            this._invalidate();
                            break;
                        case"itemRenderedAction":
                            this._createItemRenderAction();
                            break;
                        case"itemClickAction":
                            break;
                        case"itemHoldAction":
                        case"itemHoldTimeout":
                            this._attachHoldEvent();
                            break;
                        case"selectedIndex":
                            this._fireSelectItemEvent(value, prevValue);
                            break;
                        case"itemSelectAction":
                            break;
                        default:
                            this.callBase(name, value, prevValue)
                    }
                },
                _expectNextPageLoading: function() {
                    this._startIndexForAppendedItems = 0
                },
                _expectLastItemLoading: function() {
                    this._startIndexForAppendedItems = -1
                },
                _forgetNextPageLoading: function() {
                    this._startIndexForAppendedItems = null
                },
                _handleDataSourceChanged: function(newItems) {
                    var items = this.option("items");
                    if (this._initialized && items && this._shouldAppendItems()) {
                        this._renderedItemsCount = items.length;
                        if (!this._dataSource.isLastPage() || this._startIndexForAppendedItems !== -1)
                            this.option().items = items.concat(newItems.slice(this._startIndexForAppendedItems));
                        this._renderContent();
                        this._forgetNextPageLoading()
                    }
                    else
                        this.option("items", newItems)
                },
                _handleDataSourceLoadError: function() {
                    this._forgetNextPageLoading()
                },
                _shouldAppendItems: function() {
                    return this._startIndexForAppendedItems != null && this._allowDinamicItemsAppend()
                },
                _allowDinamicItemsAppend: function() {
                    return false
                },
                _clean: function() {
                    this._itemContainer().empty()
                },
                _refresh: function() {
                    this._cleanRenderedItems();
                    this.callBase.apply(this, arguments)
                },
                _itemContainer: function() {
                    return this._element()
                },
                _itemClass: DX.abstract,
                _itemSelector: function() {
                    return "." + this._itemClass()
                },
                _itemDataKey: DX.abstract,
                _itemElements: function() {
                    return this._itemContainer().find(this._itemSelector())
                },
                _render: function() {
                    this.callBase();
                    this._attachClickEvent();
                    this._attachHoldEvent();
                    if (this._selectionEnabled()) {
                        this._renderSelectedIndex(this.option("selectedIndex"));
                        this._attachSelectedEvent()
                    }
                },
                _selectionEnabled: function() {
                    return this._renderSelectedIndex !== DX.abstract
                },
                _selectionByClickEnabled: function() {
                    return true
                },
                _renderSelectedIndex: DX.abstract,
                _attachSelectedEvent: function() {
                    if (!this._selectionByClickEnabled())
                        return;
                    var itemSelector = this._itemSelector(),
                        itemSelectHandler = this._createAction($.proxy(function(e) {
                            this._handleItemSelect(e.jQueryEvent)
                        }, this)),
                        eventName = events.addNamespace("dxclick", this.NAME);
                    this._element().off(eventName, itemSelector).on(eventName, itemSelector, $.proxy(function(e) {
                        var $itemElement = $(e.target).closest(itemSelector);
                        itemSelectHandler({
                            itemElement: $itemElement,
                            jQueryEvent: e
                        });
                        this._handleItemClick(e)
                    }, this))
                },
                _handleItemSelect: function(e) {
                    if (events.needSkipEvent(e))
                        return;
                    var items = this.option("items"),
                        selectedItem = $(e.currentTarget).data(this._itemDataKey()),
                        selectedItemIndex = $.inArray(selectedItem, items);
                    this.option("selectedIndex", selectedItemIndex)
                },
                _updateSelectedIndex: function() {
                    this._renderSelectedIndex.apply(this, arguments)
                },
                _selectedItemElement: function(index) {
                    return this._itemElements().eq(index)
                },
                _attachClickEvent: function() {
                    if (this._selectionEnabled() && this._selectionByClickEnabled())
                        return;
                    var itemSelector = this._itemSelector(),
                        eventName = events.addNamespace("dxclick", this.NAME);
                    this._itemContainer().off(eventName, itemSelector).on(eventName, itemSelector, $.proxy(this._handleItemClick, this))
                },
                _handleItemClick: function(e) {
                    this._handleItemJQueryEvent(e, "itemClickAction")
                },
                _attachHoldEvent: function() {
                    var $itemContainer = this._itemContainer(),
                        itemSelector = this._itemSelector(),
                        eventName = events.addNamespace("dxhold", this.NAME);
                    $itemContainer.off(eventName, itemSelector);
                    if (this._shouldAttachHoldEvent())
                        $itemContainer.on(eventName, itemSelector, {timeout: this.option("itemHoldTimeout")}, $.proxy(this._handleItemHold, this))
                },
                _shouldAttachHoldEvent: function() {
                    return this.option("itemHoldAction")
                },
                _handleItemHold: function(e) {
                    this._handleItemJQueryEvent(e, "itemHoldAction")
                },
                _renderContentImpl: function() {
                    var items = this.option("items") || [];
                    if (this._renderedItemsCount)
                        this._renderItems(items.slice(this._renderedItemsCount));
                    else
                        this._renderItems(items)
                },
                _renderItems: function(items) {
                    if (items.length)
                        $.each(items, $.proxy(this._renderItem, this));
                    this._renderEmptyMessage()
                },
                _renderItem: function(index, itemData, container) {
                    container = container || this._itemContainer();
                    var itemRenderer = this._getItemRenderer(),
                        itemTemplateName = this._getItemTemplateName(itemData),
                        itemTemplate = this._getTemplate(itemTemplateName, index, itemData),
                        itemElement,
                        renderArgs = {
                            index: index,
                            item: itemData,
                            container: container
                        };
                    if (itemRenderer)
                        itemElement = this._createItemByRenderer(itemRenderer, renderArgs);
                    else if (itemTemplate)
                        itemElement = this._createItemByTemplate(itemTemplate, renderArgs);
                    else
                        itemElement = this._createItemByRenderer(this._itemRenderDefault, renderArgs);
                    itemElement.addClass(this._itemClass()).data(this._itemDataKey(), itemData);
                    var postprocessRenderArgs = {
                            itemElement: itemElement,
                            itemData: itemData,
                            itemIndex: index
                        };
                    this._postprocessRenderItem(postprocessRenderArgs);
                    this._getItemRenderAction()({
                        itemElement: itemElement,
                        itemData: itemData
                    });
                    return itemElement
                },
                _createItemRenderAction: function() {
                    return this._itemRenderAction = this._createActionByOption("itemRenderedAction", {
                            element: this._element(),
                            excludeValidators: ["gesture", "designMode", "disabled"]
                        })
                },
                _getItemRenderAction: function() {
                    return this._itemRenderAction || this._createItemRenderAction()
                },
                _getItemRenderer: function() {
                    this._itemRender = this._itemRender || this.option("itemRender");
                    return this._itemRender
                },
                _createItemByRenderer: function(itemRenderer, renderArgs) {
                    var itemElement = $("<div />").appendTo(renderArgs.container);
                    var rendererResult = itemRenderer.call(this, renderArgs.item, renderArgs.index, itemElement);
                    if (rendererResult != null && itemElement[0] !== rendererResult[0])
                        itemElement.append(rendererResult);
                    return itemElement
                },
                _getItemTemplateName: function(itemData) {
                    return itemData && itemData.template || this.option("itemTemplate")
                },
                _createItemByTemplate: function(itemTemplate, renderArgs) {
                    return itemTemplate.render(renderArgs.container, renderArgs.item, renderArgs.index, "ignoreTarget")
                },
                _itemRenderDefault: function(item, index, itemElement) {
                    if ($.isPlainObject(item)) {
                        if (item.visible !== undefined && !item.visible)
                            itemElement.hide();
                        if (item.disabled)
                            itemElement.addClass("dx-state-disabled");
                        if (item.text)
                            itemElement.text(item.text);
                        if (item.html)
                            itemElement.html(item.html)
                    }
                    else
                        itemElement.html(String(item))
                },
                _postprocessRenderItem: $.noop,
                _renderEmptyMessage: function() {
                    if (!this._selectionEnabled()) {
                        var noDataText = this.option("noDataText"),
                            items = this.option("items"),
                            dataSourceLoading = this._dataSource && this._dataSource.isLoading(),
                            hideNoData = !noDataText || items && items.length || dataSourceLoading;
                        if (hideNoData && this._$nodata) {
                            this._$nodata.remove();
                            this._$nodata = null
                        }
                        if (!hideNoData) {
                            this._$nodata = this._$nodata || $("<div />").addClass("dx-empty-message");
                            this._$nodata.appendTo(this._itemContainer()).text(noDataText)
                        }
                    }
                },
                _handleItemJQueryEvent: function(jQueryEvent, handlerOptionName, actionArgs, actionConfig) {
                    this._handleItemEvent(jQueryEvent.target, handlerOptionName, $.extend(actionArgs, {jQueryEvent: jQueryEvent}), actionConfig)
                },
                _handleItemEvent: function(initiator, handlerOptionName, actionArgs, actionConfig) {
                    var action = this._createActionByOption(handlerOptionName, actionConfig);
                    return this._handleItemEventImpl(initiator, action, actionArgs)
                },
                _handleItemEventByHandler: function(initiator, handler, actionArgs, actionConfig) {
                    var action = this._createAction(handler, actionConfig);
                    return this._handleItemEventImpl(initiator, action, actionArgs)
                },
                _handleItemEventImpl: function(initiator, action, actionArgs) {
                    var $itemElement = this._closestItemElement($(initiator));
                    actionArgs = $.extend({
                        itemElement: $itemElement,
                        itemData: this._getItemData($itemElement)
                    }, actionArgs);
                    return action(actionArgs)
                },
                _closestItemElement: function($element) {
                    return $($element).closest(this._itemSelector())
                },
                _getItemData: function($itemElement) {
                    return $itemElement.data(this._itemDataKey())
                },
                itemElements: function() {
                    return this._itemElements()
                },
                itemsContainer: function() {
                    return this._itemContainer()
                }
            }).include(ui.DataHelperMixin);
        ui.CollectionContainerWidget = CollectionContainerWidget
    })(jQuery, DevExpress);
    /*! Module core, file ui.tooltip.js */
    (function($, DX, undefined) {
        var $tooltip = null;
        var createTooltip = function(options) {
                options = $.extend({position: "top"}, options);
                var content = options.content;
                delete options.content;
                return $("<div />").html(content).appendTo(DX.overlayTargetContainer()).dxTooltip(options)
            };
        var removeTooltip = function() {
                if (!$tooltip)
                    return;
                $tooltip.remove();
                $tooltip = null
            };
        var tooltip = {
                show: function(options) {
                    removeTooltip();
                    $tooltip = createTooltip(options);
                    return $tooltip.dxTooltip("show")
                },
                hide: function() {
                    if (!$tooltip)
                        return $.when();
                    return $tooltip.dxTooltip("hide").done(removeTooltip).promise()
                }
            };
        DX.ui.tooltip = tooltip
    })(jQuery, DevExpress)
}
if (!DevExpress.MOD_WIDGETS_BASE) {
    if (!window.DevExpress)
        throw Error('Required module is not referenced: core');
    /*! Module widgets-base, file ui.scrollable.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var SCROLLABLE = "dxScrollable",
            SCROLLABLE_STRATEGY = "dxScrollableStrategy",
            SCROLLABLE_CLASS = "dx-scrollable",
            SCROLLABLE_DISABLED_CLASS = "dx-scrollable-disabled",
            SCROLLABLE_CONTAINER_CLASS = "dx-scrollable-container",
            SCROLLABLE_CONTENT_CLASS = "dx-scrollable-content",
            VERTICAL = "vertical",
            HORIZONTAL = "horizontal",
            BOTH = "both";
        DX.registerComponent(SCROLLABLE, DX.DOMComponent.inherit({
            NAMESPACE: ui,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    disabled: false,
                    scrollAction: null,
                    direction: VERTICAL,
                    showScrollbar: true,
                    useNative: true,
                    updateAction: null,
                    useSimulatedScrollbar: false,
                    useKeyboard: true,
                    inertiaEnabled: true,
                    bounceEnabled: true,
                    scrollByContent: true,
                    scrollByThumb: false,
                    startAction: null,
                    endAction: null,
                    bounceAction: null,
                    stopAction: null
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function(device) {
                                return !DX.support.nativeScrolling
                            },
                            options: {
                                useNative: false,
                                useSimulatedScrollbar: true
                            }
                        }, {
                            device: function(device) {
                                return !DX.support.nativeScrolling && !DX.devices.isSimulator() && DX.devices.real().platform === "generic" && device.platform === "generic"
                            },
                            options: {
                                scrollByThumb: true,
                                scrollByContent: false,
                                showScrollbar: "onHover",
                                bounceEnabled: false
                            }
                        }, {
                            device: function(device) {
                                return DX.support.nativeScrolling && DX.devices.real().platform === "android"
                            },
                            options: {useSimulatedScrollbar: true}
                        }])
            },
            _init: function() {
                this.callBase();
                this._initMarkup();
                this._attachNativeScrollbarsCustomizationCss();
                this._locked = false
            },
            _visibilityChanged: function(visible) {
                if (visible) {
                    this.update();
                    this._savedScrollOffset && this.scrollTo(this._savedScrollOffset)
                }
                else
                    this._savedScrollOffset = this.scrollOffset()
            },
            _initMarkup: function() {
                var $element = this._element().addClass(SCROLLABLE_CLASS),
                    $container = this._$container = $("<div>").addClass(SCROLLABLE_CONTAINER_CLASS),
                    $content = this._$content = $("<div>").addClass(SCROLLABLE_CONTENT_CLASS);
                $content.append($element.contents()).appendTo($container);
                $container.appendTo($element)
            },
            _dimensionChanged: function() {
                this.update()
            },
            _attachNativeScrollbarsCustomizationCss: function() {
                if (!(navigator.platform.indexOf('Mac') > -1 && DevExpress.browser['webkit']))
                    this._element().addClass("dx-scrollable-customizable-scrollbars")
            },
            _render: function() {
                this._renderDirection();
                this._renderStrategy();
                this._attachEventHandlers();
                this._renderDisabledState();
                this._createActions();
                this.update();
                this.callBase()
            },
            _toggleRTLDirection: function(rtl) {
                this.callBase(rtl);
                if (rtl)
                    this.scrollTo({left: this.scrollWidth() - this.clientWidth()})
            },
            _attachEventHandlers: function() {
                var strategy = this._strategy;
                var initEventData = {
                        getDirection: $.proxy(strategy.getDirection, strategy),
                        validate: $.proxy(strategy.validate, strategy)
                    };
                this._$container.off("." + SCROLLABLE).on(events.addNamespace("scroll", SCROLLABLE), $.proxy(strategy.handleScroll, strategy)).on(events.addNamespace("dxscrollinit", SCROLLABLE), initEventData, $.proxy(this._handleInit, this)).on(events.addNamespace("dxscrollstart", SCROLLABLE), $.proxy(strategy.handleStart, strategy)).on(events.addNamespace("dxscroll", SCROLLABLE), $.proxy(strategy.handleMove, strategy)).on(events.addNamespace("dxscrollend", SCROLLABLE), $.proxy(strategy.handleEnd, strategy)).on(events.addNamespace("dxscrollcancel", SCROLLABLE), $.proxy(strategy.handleCancel, strategy)).on(events.addNamespace("dxscrollstop", SCROLLABLE), $.proxy(strategy.handleStop, strategy))
            },
            _handleInit: function() {
                this.update();
                var strategy = this._strategy;
                strategy.handleInit.apply(strategy, arguments)
            },
            _renderDisabledState: function() {
                this._element().toggleClass(SCROLLABLE_DISABLED_CLASS, this.option("disabled"));
                if (this.option("disabled"))
                    this._lock();
                else
                    this._unlock()
            },
            _renderDirection: function() {
                this._element().removeClass("dx-scrollable-" + HORIZONTAL).removeClass("dx-scrollable-" + VERTICAL).removeClass("dx-scrollable-" + BOTH).addClass("dx-scrollable-" + this.option("direction"))
            },
            _renderStrategy: function() {
                this._createStrategy();
                this._strategy.render();
                this._element().data(SCROLLABLE_STRATEGY, this._strategy)
            },
            _createStrategy: function() {
                this._strategy = this.option("useNative") ? new ui.NativeScrollableStrategy(this) : new ui.SimulatedScrollableStrategy(this)
            },
            _createActions: function() {
                this._strategy.createActions()
            },
            _clean: function() {
                this._strategy.dispose()
            },
            _optionChanged: function(optionName, optionValue) {
                switch (optionName) {
                    case"startAction":
                    case"endAction":
                    case"stopAction":
                    case"updateAction":
                    case"scrollAction":
                    case"bounceAction":
                        this._createActions();
                        break;
                    case"direction":
                        this._resetInactiveDirection();
                        this._invalidate();
                        break;
                    case"inertiaEnabled":
                    case"bounceEnabled":
                    case"scrollByContent":
                    case"scrollByThumb":
                    case"bounceEnabled":
                    case"useNative":
                    case"useKeyboard":
                    case"showScrollbar":
                    case"useSimulatedScrollbar":
                        this._invalidate();
                        break;
                    case"disabled":
                        this._renderDisabledState();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _resetInactiveDirection: function() {
                var inactiveProp = this._getInactiveProp();
                if (!inactiveProp)
                    return;
                var scrollOffset = this.scrollOffset();
                scrollOffset[inactiveProp] = 0;
                this.scrollTo(scrollOffset)
            },
            _getInactiveProp: function() {
                var direction = this.option("direction");
                if (direction === VERTICAL)
                    return "left";
                if (direction === HORIZONTAL)
                    return "top"
            },
            _location: function() {
                return this._strategy.location()
            },
            _normalizeLocation: function(location) {
                var direction = this.option("direction");
                return {
                        left: $.isPlainObject(location) ? -(location.left || location.x || 0) : direction !== VERTICAL ? -location : 0,
                        top: $.isPlainObject(location) ? -(location.top || location.y || 0) : direction !== HORIZONTAL ? -location : 0
                    }
            },
            _isLocked: function() {
                return this._locked
            },
            _lock: function() {
                this._locked = true
            },
            _unlock: function() {
                this._locked = false
            },
            _isDirection: function(direction) {
                var current = this.option("direction");
                if (direction === VERTICAL)
                    return current !== HORIZONTAL;
                if (direction === HORIZONTAL)
                    return current !== VERTICAL;
                return current === direction
            },
            _updateAllowedDirection: function() {
                var allowedDirections = this._strategy._allowedDirections();
                if (this._isDirection(BOTH) && allowedDirections.vertical && allowedDirections.horizontal)
                    this._allowedDirectionValue = BOTH;
                else if (this._isDirection(HORIZONTAL) && allowedDirections.horizontal)
                    this._allowedDirectionValue = HORIZONTAL;
                else if (this._isDirection(VERTICAL) && allowedDirections.vertical)
                    this._allowedDirectionValue = VERTICAL;
                else
                    this._allowedDirectionValue = null
            },
            _allowedDirection: function() {
                return this._allowedDirectionValue
            },
            content: function() {
                return this._$content
            },
            scrollOffset: function() {
                var location = this._location();
                return {
                        top: -location.top,
                        left: -location.left
                    }
            },
            scrollTop: function() {
                return this.scrollOffset().top
            },
            scrollLeft: function() {
                return this.scrollOffset().left
            },
            clientHeight: function() {
                return this._$container.height()
            },
            scrollHeight: function() {
                return this.content().height()
            },
            clientWidth: function() {
                return this._$container.width()
            },
            scrollWidth: function() {
                return this.content().width()
            },
            update: function() {
                this._strategy.update();
                this._updateAllowedDirection();
                return $.Deferred().resolve().promise()
            },
            scrollBy: function(distance) {
                distance = this._normalizeLocation(distance);
                this._strategy.scrollBy(distance)
            },
            scrollTo: function(targetLocation) {
                targetLocation = this._normalizeLocation(targetLocation);
                var location = this._location();
                this.scrollBy({
                    left: location.left - targetLocation.left,
                    top: location.top - targetLocation.top
                })
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollbar.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var SCROLLBAR = "dxScrollbar",
            SCROLLABLE_SCROLLBAR_CLASS = "dx-scrollable-scrollbar",
            SCROLLABLE_SCROLLBAR_ACTIVE_CLASS = SCROLLABLE_SCROLLBAR_CLASS + "-active",
            SCROLLABLE_SCROLL_CLASS = "dx-scrollable-scroll",
            SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden",
            VERTICAL = "vertical",
            HORIZONTAL = "horizontal",
            THUMB_MIN_SIZE = 15;
        var SCROLLBAR_VISIBLE = {
                onScroll: "onScroll",
                onHover: "onHover",
                always: "always",
                never: "never"
            };
        DX.registerComponent(SCROLLBAR, ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    direction: null,
                    visible: false,
                    activeStateEnabled: false,
                    visibilityMode: SCROLLBAR_VISIBLE.onScroll,
                    containerSize: 0,
                    contentSize: 0
                })
            },
            _init: function() {
                this.callBase();
                this._isHovered = false
            },
            _render: function() {
                this._renderThumb();
                this.callBase();
                this._renderDirection();
                this._update();
                this._attachPointerDownHandler();
                this.option("hoverStateEnabled", this._isHoverMode())
            },
            _renderThumb: function() {
                this._$thumb = $("<div>").addClass(SCROLLABLE_SCROLL_CLASS);
                this._element().addClass(SCROLLABLE_SCROLLBAR_CLASS).append(this._$thumb)
            },
            isThumb: function($element) {
                return !!this._element().find($element).length
            },
            _isHoverMode: function() {
                return this.option("visibilityMode") === SCROLLBAR_VISIBLE.onHover
            },
            _renderDirection: function() {
                var direction = this.option("direction");
                this._element().addClass("dx-scrollbar-" + direction);
                this._dimension = direction === HORIZONTAL ? "width" : "height";
                this._prop = direction === HORIZONTAL ? "left" : "top"
            },
            _attachPointerDownHandler: function() {
                this._$thumb.on(events.addNamespace("dxpointerdown", SCROLLBAR), $.proxy(this.feedbackOn, this))
            },
            feedbackOn: function() {
                this._element().addClass(SCROLLABLE_SCROLLBAR_ACTIVE_CLASS);
                activeScrollbar = this
            },
            feedbackOff: function() {
                this._element().removeClass(SCROLLABLE_SCROLLBAR_ACTIVE_CLASS);
                activeScrollbar = null
            },
            cursorEnter: function() {
                this._isHovered = true;
                this.option("visible", true)
            },
            cursorLeave: function() {
                this._isHovered = false;
                this.option("visible", false)
            },
            _renderDimensions: function() {
                this._$thumb.height(this.option("height"));
                this._$thumb.width(this.option("width"))
            },
            _toggleVisibility: function(visible) {
                visible = this._adjustVisibility(visible);
                this.option().visible = visible;
                this._$thumb.toggleClass("dx-state-invisible", !visible)
            },
            _adjustVisibility: function(visible) {
                if (this.containerToContentRatio() && !this._needScrollbar())
                    return false;
                switch (this.option("visibilityMode")) {
                    case SCROLLBAR_VISIBLE.onScroll:
                        break;
                    case SCROLLBAR_VISIBLE.onHover:
                        visible = visible || !!this._isHovered;
                        break;
                    case SCROLLBAR_VISIBLE.never:
                        visible = false;
                        break;
                    case SCROLLBAR_VISIBLE.always:
                        visible = true;
                        break
                }
                return visible
            },
            moveTo: function(location) {
                if (this._isHidden())
                    return;
                if ($.isPlainObject(location))
                    location = location[this._prop] || 0;
                var scrollBarLocation = {};
                scrollBarLocation[this._prop] = this._calculateScrollBarPosition(location);
                DX.translator.move(this._$thumb, scrollBarLocation)
            },
            _calculateScrollBarPosition: function(location) {
                return -location * this._thumbRatio
            },
            _update: function() {
                var containerSize = this.option("containerSize"),
                    contentSize = this.option("contentSize");
                this._containerToContentRatio = containerSize / contentSize;
                var thumbSize = Math.round(Math.max(Math.round(containerSize * this._containerToContentRatio), THUMB_MIN_SIZE));
                this._thumbRatio = (containerSize - thumbSize) / (contentSize - containerSize);
                this.option(this._dimension, thumbSize);
                this._element().toggle(this._needScrollbar())
            },
            _isHidden: function() {
                return this.option("visibilityMode") === SCROLLBAR_VISIBLE.never
            },
            _needScrollbar: function() {
                return !this._isHidden() && this._containerToContentRatio < 1
            },
            containerToContentRatio: function() {
                return this._containerToContentRatio
            },
            _normalizeSize: function(size) {
                return $.isPlainObject(size) ? size[this._dimension] || 0 : size
            },
            _clean: function() {
                this.callBase();
                if (this === activeScrollbar)
                    activeScrollbar = null;
                this._$thumb.off("." + SCROLLBAR)
            },
            _optionChanged: function(name, value) {
                if (this._isHidden())
                    return;
                switch (name) {
                    case"containerSize":
                    case"contentSize":
                        this.option()[name] = this._normalizeSize(value);
                        this._update();
                        break;
                    case"visibilityMode":
                    case"direction":
                        this._invalidate();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        var activeScrollbar = null;
        $(document).on(events.addNamespace("dxpointerup", SCROLLBAR), function() {
            if (activeScrollbar)
                activeScrollbar.feedbackOff()
        })
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollable.native.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils,
            devices = DX.devices,
            abs = Math.abs;
        var SCROLLABLE_NATIVE = "dxNativeScrollable",
            SCROLLABLE_NATIVE_CLASS = "dx-scrollable-native",
            SCROLLABLE_SCROLLBAR_SIMULATED = "dx-scrollable-scrollbar-simulated",
            SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden",
            VERTICAL = "vertical",
            HORIZONTAL = "horizontal",
            GESTURE_LOCK_KEY = "dxGestureLock",
            GESTURE_LOCK_TIMEOUT = 400,
            HIDE_SCROLLBAR_TIMOUT = 500;
        ui.NativeScrollableStrategy = DX.Class.inherit({
            ctor: function(scrollable) {
                this._init(scrollable)
            },
            _init: function(scrollable) {
                this._component = scrollable;
                this._$element = scrollable._element();
                this._$container = scrollable._$container;
                this._$content = scrollable._$content;
                this._direction = scrollable.option("direction");
                this._useSimulatedScrollbar = scrollable.option("useSimulatedScrollbar");
                this._showScrollbar = scrollable.option("showScrollbar");
                this.option = $.proxy(scrollable.option, scrollable);
                this._createActionByOption = $.proxy(scrollable._createActionByOption, scrollable);
                this._isLocked = $.proxy(scrollable._isLocked, scrollable);
                this._isDirection = $.proxy(scrollable._isDirection, scrollable);
                this._allowedDirection = $.proxy(scrollable._allowedDirection, scrollable)
            },
            render: function() {
                this._$element.addClass(SCROLLABLE_NATIVE_CLASS).addClass(SCROLLABLE_NATIVE_CLASS + "-" + devices.real().platform).toggleClass(SCROLLABLE_SCROLLBARS_HIDDEN, !this._showScrollbar);
                if (this._showScrollbar && this._useSimulatedScrollbar)
                    this._renderScrollbars()
            },
            _renderScrollbars: function() {
                this._scrollbars = {};
                this._hideScrollbarTimeout = 0;
                this._$element.addClass(SCROLLABLE_SCROLLBAR_SIMULATED);
                this._renderScrollbar(VERTICAL);
                this._renderScrollbar(HORIZONTAL)
            },
            _renderScrollbar: function(direction) {
                if (!this._isDirection(direction))
                    return;
                var $scrollbar = $("<div>").dxScrollbar({direction: direction}).appendTo(this._$element);
                this._scrollbars[direction] = $scrollbar.dxScrollbar("instance")
            },
            handleInit: $.noop,
            handleStart: $.noop,
            handleMove: function(e) {
                if (this._isLocked()) {
                    e.cancel = true;
                    return
                }
                if (this._allowedDirection())
                    e.originalEvent.originalEvent.isScrollingEvent = true
            },
            handleEnd: $.noop,
            handleStop: $.noop,
            _eachScrollbar: function(callback) {
                callback = $.proxy(callback, this);
                $.each(this._scrollbars || {}, function(direction, scrollbar) {
                    callback(scrollbar, direction)
                })
            },
            createActions: function() {
                var actionConfig = {excludeValidators: ["gesture"]};
                this._scrollAction = this._createActionByOption("scrollAction", actionConfig);
                this._updateAction = this._createActionByOption("updateAction", actionConfig)
            },
            _createActionArgs: function() {
                var location = this.location();
                return {
                        jQueryEvent: this._eventForUserAction,
                        scrollOffset: {
                            top: -location.top,
                            left: -location.left
                        },
                        reachedLeft: this._isDirection(HORIZONTAL) ? location.left >= 0 : undefined,
                        reachedRight: this._isDirection(HORIZONTAL) ? location.left <= this._containerSize.width - this._componentContentSize.width : undefined,
                        reachedTop: this._isDirection(VERTICAL) ? location.top >= 0 : undefined,
                        reachedBottom: this._isDirection(VERTICAL) ? location.top <= this._containerSize.height - this._componentContentSize.height : undefined
                    }
            },
            handleScroll: function(e) {
                if (!this._isScrollLocationChanged()) {
                    e.stopImmediatePropagation();
                    return
                }
                this._eventForUserAction = e;
                this._moveScrollbars();
                this._scrollAction(this._createActionArgs());
                this._treatNativeGesture();
                this._lastLocation = this.location()
            },
            _isScrollLocationChanged: function() {
                var currentLocation = this.location(),
                    lastLocation = this._lastLocation || {},
                    isTopChanged = lastLocation.top !== currentLocation.top,
                    isLeftChanged = lastLocation.left !== currentLocation.left;
                return isTopChanged || isLeftChanged
            },
            _moveScrollbars: function() {
                this._eachScrollbar(function(scrollbar) {
                    scrollbar.moveTo(this.location());
                    scrollbar.option("visible", true)
                });
                this._hideScrollbars()
            },
            _hideScrollbars: function() {
                clearTimeout(this._hideScrollbarTimeout);
                this._hideScrollbarTimeout = setTimeout($.proxy(function() {
                    this._eachScrollbar(function(scrollbar) {
                        scrollbar.option("visible", false)
                    })
                }, this), HIDE_SCROLLBAR_TIMOUT)
            },
            _treatNativeGesture: function() {
                this._prepareGesture();
                this._forgetGesture()
            },
            _prepareGesture: function() {
                if (this._gestureEndTimer) {
                    clearTimeout(this._gestureEndTimer);
                    this._gestureEndTimer = null
                }
                else
                    this._$element.data(GESTURE_LOCK_KEY, true)
            },
            _forgetGesture: function() {
                this._gestureEndTimer = setTimeout($.proxy(function() {
                    this._$element.data(GESTURE_LOCK_KEY, false);
                    this._gestureEndTimer = null
                }, this), GESTURE_LOCK_TIMEOUT)
            },
            location: function() {
                return {
                        left: -this._$container.scrollLeft(),
                        top: -this._$container.scrollTop()
                    }
            },
            disabledChanged: $.noop,
            update: function() {
                this._update();
                this._updateAction(this._createActionArgs())
            },
            _update: function() {
                this._updateDimensions();
                this._updateScrollbars()
            },
            _updateDimensions: function() {
                this._containerSize = {
                    height: this._$container.height(),
                    width: this._$container.width()
                };
                this._componentContentSize = {
                    height: this._component.content().height(),
                    width: this._component.content().width()
                };
                this._contentSize = {
                    height: this._$content.height(),
                    width: this._$content.width()
                }
            },
            _updateScrollbars: function() {
                this._eachScrollbar(function(scrollbar, direction) {
                    var dimension = direction === VERTICAL ? "height" : "width";
                    scrollbar.option({
                        containerSize: this._containerSize[dimension],
                        contentSize: this._componentContentSize[dimension]
                    })
                })
            },
            _allowedDirections: function() {
                return {
                        vertical: this._isDirection(VERTICAL) && this._contentSize.height > this._containerSize.height,
                        horizontal: this._isDirection(HORIZONTAL) && this._contentSize.width > this._containerSize.width
                    }
            },
            dispose: function() {
                this._$element.removeClass(function(index, className) {
                    var scrollableNativeRegexp = new RegExp(SCROLLABLE_NATIVE_CLASS + "\\S*", "g");
                    if (scrollableNativeRegexp.test(className))
                        return className.match(scrollableNativeRegexp).join(" ")
                });
                this._$element.off("." + SCROLLABLE_NATIVE);
                this._$container.off("." + SCROLLABLE_NATIVE);
                this._removeScrollbars();
                clearTimeout(this._gestureEndTimer)
            },
            _removeScrollbars: function() {
                this._eachScrollbar(function(scrollbar) {
                    scrollbar._element().remove()
                })
            },
            scrollBy: function(distance) {
                var location = this.location();
                this._$container.scrollTop(-location.top - distance.top);
                this._$container.scrollLeft(-location.left - distance.left)
            },
            validate: function() {
                return !this.option("disabled") && (this._allowedDirection() || this._isDirection(VERTICAL))
            },
            getDirection: function() {
                return this._allowedDirection()
            }
        })
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollable.simulated.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            math = Math;
        var realDevice = DX.devices.real;
        var isSluggishPlatform = realDevice.platform === "win8" || realDevice.platform === "android";
        var SCROLLABLE_SIMULATED = "dxSimulatedScrollable",
            SCROLLABLE_STRATEGY = "dxScrollableStrategy",
            SCROLLABLE_SIMULATED_CURSOR = SCROLLABLE_SIMULATED + "Cursor",
            SCROLLABLE_SIMULATED_KEYBOARD = SCROLLABLE_SIMULATED + "Keyboard",
            SCROLLABLE_SIMULATED_CLASS = "dx-scrollable-simulated",
            SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden",
            VERTICAL = "vertical",
            HORIZONTAL = "horizontal",
            ACCELERATION = isSluggishPlatform ? 0.95 : 0.92,
            OUT_BOUNDS_ACCELERATION = 0.5,
            MIN_VELOCITY_LIMIT = 1,
            FRAME_DURATION = math.round(1000 / 60),
            SCROLL_LINE_HEIGHT = 20,
            BOUNCE_MIN_VELOCITY_LIMIT = MIN_VELOCITY_LIMIT / 5,
            BOUNCE_DURATION = isSluggishPlatform ? 300 : 400,
            BOUNCE_FRAMES = BOUNCE_DURATION / FRAME_DURATION,
            BOUNCE_ACCELERATION_SUM = (1 - math.pow(ACCELERATION, BOUNCE_FRAMES)) / (1 - ACCELERATION);
        var KEY_CODES = {
                PAGE_UP: 33,
                PAGE_DOWN: 34,
                END: 35,
                HOME: 36,
                LEFT: 37,
                UP: 38,
                RIGHT: 39,
                DOWN: 40
            };
        var InertiaAnimator = DX.Animator.inherit({
                ctor: function(scroller) {
                    this.callBase();
                    this.scroller = scroller
                },
                VELOCITY_LIMIT: MIN_VELOCITY_LIMIT,
                _isFinished: function() {
                    return math.abs(this.scroller._velocity) <= this.VELOCITY_LIMIT
                },
                _step: function() {
                    this.scroller._scrollStep(this.scroller._velocity);
                    this.scroller._velocity *= this._acceleration()
                },
                _acceleration: function() {
                    return this.scroller._inBounds() ? ACCELERATION : OUT_BOUNDS_ACCELERATION
                },
                _complete: function() {
                    this.scroller._scrollComplete()
                },
                _stop: function() {
                    this.scroller._stopComplete()
                }
            });
        var BounceAnimator = InertiaAnimator.inherit({
                VELOCITY_LIMIT: BOUNCE_MIN_VELOCITY_LIMIT,
                _isFinished: function() {
                    return this.scroller._crossBoundOnNextStep() || this.callBase()
                },
                _acceleration: function() {
                    return ACCELERATION
                },
                _complete: function() {
                    this.scroller._move(this.scroller._bounceLocation);
                    this.callBase()
                }
            });
        var isWheelEvent = function(e) {
                return e.type === "dxmousewheel"
            };
        var Scroller = ui.Scroller = DX.Class.inherit({
                ctor: function(options) {
                    this._initOptions(options);
                    this._initAnimators();
                    this._initScrollbar()
                },
                _initOptions: function(options) {
                    this._location = 0;
                    this._topReached = false;
                    this._bottomReached = false;
                    this._axis = options.direction === HORIZONTAL ? "x" : "y";
                    this._prop = options.direction === HORIZONTAL ? "left" : "top";
                    this._dimension = options.direction === HORIZONTAL ? "width" : "height";
                    this._scrollProp = options.direction === HORIZONTAL ? "scrollLeft" : "scrollTop";
                    $.each(options, $.proxy(function(optionName, optionValue) {
                        this["_" + optionName] = optionValue
                    }, this))
                },
                _initAnimators: function() {
                    this._inertiaAnimator = new InertiaAnimator(this);
                    this._bounceAnimator = new BounceAnimator(this)
                },
                _initScrollbar: function() {
                    this._$scrollbar = $("<div>").dxScrollbar({
                        direction: this._direction,
                        visible: this._scrollByThumb,
                        visibilityMode: this._visibilityModeNormalize(this._scrollbarVisible),
                        containerSize: this._containerSize(),
                        contentSize: this._contentSize()
                    }).appendTo(this._$container);
                    this._scrollbar = this._$scrollbar.dxScrollbar("instance")
                },
                _visibilityModeNormalize: function(mode) {
                    return mode === true ? "onScroll" : mode === false ? "never" : mode
                },
                _scrollStep: function(delta) {
                    var prevLocation = this._location;
                    this._location += delta;
                    this._suppressBounce();
                    this._move();
                    if (prevLocation !== this._location) {
                        this._scrollAction();
                        this._$element.triggerHandler("scroll")
                    }
                },
                _suppressBounce: function() {
                    if (this._bounceEnabled || this._inBounds(this._location))
                        return;
                    this._velocity = 0;
                    this._location = this._boundLocation()
                },
                _boundLocation: function() {
                    var location = math.min(this._location, this._maxOffset);
                    return math.max(location, this._minOffset)
                },
                _move: function(location) {
                    this._location = location !== undefined ? location : this._location;
                    this._moveContent();
                    this._moveScrollbar()
                },
                _moveContent: function() {
                    var targetLocation = {};
                    targetLocation[this._prop] = this._location;
                    DX.translator.move(this._$content, targetLocation)
                },
                _moveScrollbar: function() {
                    this._scrollbar.moveTo(this._location)
                },
                _scrollComplete: function() {
                    if (this._inBounds()) {
                        this._hideScrollbar();
                        this._correctLocation();
                        if (this._completeDeferred)
                            this._completeDeferred.resolve()
                    }
                    this._scrollToBounds()
                },
                _correctLocation: function() {
                    this._location = math.round(this._location);
                    this._move()
                },
                _scrollToBounds: function() {
                    if (this._inBounds())
                        return;
                    this._bounceAction();
                    this._setupBounce();
                    this._bounceAnimator.start()
                },
                _setupBounce: function() {
                    var boundLocation = this._bounceLocation = this._boundLocation(),
                        bounceDistance = boundLocation - this._location;
                    this._velocity = bounceDistance / BOUNCE_ACCELERATION_SUM
                },
                _inBounds: function(location) {
                    location = location !== undefined ? location : this._location;
                    return location >= this._minOffset && location <= this._maxOffset
                },
                _crossBoundOnNextStep: function() {
                    var location = this._location,
                        nextLocation = location + this._velocity;
                    return location < this._minOffset && nextLocation >= this._minOffset || location > this._maxOffset && nextLocation <= this._maxOffset
                },
                _handleInit: function(e) {
                    this._stopDeferred = $.Deferred();
                    this._stopScrolling();
                    this._prepareThumbScrolling(e);
                    return this._stopDeferred.promise()
                },
                _stopScrolling: function() {
                    this._hideScrollbar();
                    this._inertiaAnimator.stop();
                    this._bounceAnimator.stop()
                },
                _prepareThumbScrolling: function(e) {
                    if (isWheelEvent(e.originalEvent))
                        return;
                    var $target = $(e.originalEvent.target);
                    var scrollbarClicked = this._isScrollbar($target);
                    if (scrollbarClicked)
                        this._moveToMouseLocation(e);
                    this._thumbScrolling = scrollbarClicked || this._isThumb($target);
                    if (this._thumbScrolling)
                        this._scrollbar.feedbackOn()
                },
                _moveToMouseLocation: function(e) {
                    var mouseLocation = e["page" + this._axis.toUpperCase()] - this._$element.offset()[this._prop];
                    var location = this._location + mouseLocation / this._containerToContentRatio() - this._$container.height() / 2;
                    this._scrollStep(-location)
                },
                _stopComplete: function() {
                    if (this._stopDeferred)
                        this._stopDeferred.resolve()
                },
                _handleStart: function() {
                    this._showScrollbar()
                },
                _handleMove: function(delta) {
                    delta = delta[this._axis];
                    if (this._thumbScrolling)
                        delta = -delta / this._containerToContentRatio();
                    if (!this._inBounds())
                        delta *= OUT_BOUNDS_ACCELERATION;
                    this._scrollStep(delta)
                },
                _containerToContentRatio: function() {
                    return this._scrollbar.containerToContentRatio()
                },
                _handleEnd: function(velocity) {
                    this._completeDeferred = $.Deferred();
                    this._velocity = velocity[this._axis];
                    this._handleInertia();
                    this._resetThumbScrolling();
                    return this._completeDeferred.promise()
                },
                _handleInertia: function() {
                    this._suppressIntertia();
                    this._inertiaAnimator.start()
                },
                _suppressIntertia: function() {
                    if (!this._inertiaEnabled || this._thumbScrolling)
                        this._velocity = 0
                },
                _resetThumbScrolling: function() {
                    this._thumbScrolling = false
                },
                _handleStop: function() {
                    this._resetThumbScrolling();
                    this._scrollToBounds()
                },
                _handleDispose: function() {
                    this._stopScrolling();
                    this._$scrollbar.remove()
                },
                _handleUpdate: function() {
                    this._update();
                    this._moveToBounds()
                },
                _update: function() {
                    this._stopScrolling();
                    this._updateLocation();
                    this._updateBounds();
                    this._updateScrollbar();
                    this._moveScrollbar();
                    this._updateScrollbarVisibility()
                },
                _updateLocation: function() {
                    this._location = DX.translator.locate(this._$content)[this._prop]
                },
                _updateBounds: function() {
                    this._maxOffset = 0;
                    this._minOffset = math.min(this._containerSize() - this._contentSize(), 0)
                },
                _updateScrollbar: function() {
                    this._scrollbar.option({
                        containerSize: this._containerSize(),
                        contentSize: this._contentSize()
                    })
                },
                _updateScrollbarVisibility: function() {
                    this._showScrollbar();
                    this._hideScrollbar()
                },
                _moveToBounds: function() {
                    this._location = this._boundLocation();
                    this._move()
                },
                _handleCreateActions: function(actions) {
                    this._scrollAction = actions.scrollAction;
                    this._bounceAction = actions.bounceAction
                },
                _showScrollbar: function() {
                    this._scrollbar.option("visible", true)
                },
                _hideScrollbar: function() {
                    this._scrollbar.option("visible", false)
                },
                _containerSize: function() {
                    return this._$container[this._dimension]()
                },
                _contentSize: function() {
                    return this._$content[this._dimension]()
                },
                _validateEvent: function(e) {
                    var $target = $(e.originalEvent.target);
                    if (this._isThumb($target) || this._isScrollbar($target)) {
                        e.preventDefault();
                        return true
                    }
                    return this._isContent($target)
                },
                _isThumb: function($element) {
                    return this._scrollByThumb && this._scrollbar.isThumb($element)
                },
                _isScrollbar: function($element) {
                    return this._scrollByThumb && $element && $element.is(this._$scrollbar)
                },
                _isContent: function($element) {
                    return this._scrollByContent && !!$element.closest(this._$element).length
                },
                _reachedMin: function() {
                    return this._location <= this._minOffset
                },
                _reachedMax: function() {
                    return this._location >= this._maxOffset
                },
                _handleCursorEnter: function() {
                    this._scrollbar.cursorEnter()
                },
                _handleCursorLeave: function() {
                    this._scrollbar.cursorLeave()
                }
            });
        var hoveredScrollable,
            activeScrollable;
        ui.SimulatedScrollableStrategy = DX.Class.inherit({
            ctor: function(scrollable) {
                this._init(scrollable)
            },
            _init: function(scrollable) {
                this._component = scrollable;
                this._$element = scrollable._element();
                this._$container = scrollable._$container.prop("tabindex", 0);
                this._$content = scrollable._$content;
                this.option = $.proxy(scrollable.option, scrollable);
                this._createActionByOption = $.proxy(scrollable._createActionByOption, scrollable);
                this._isLocked = $.proxy(scrollable._isLocked, scrollable);
                this._isDirection = $.proxy(scrollable._isDirection, scrollable);
                this._allowedDirection = $.proxy(scrollable._allowedDirection, scrollable)
            },
            render: function() {
                this._$element.addClass(SCROLLABLE_SIMULATED_CLASS);
                this._createScrollers();
                this._attachKeyboardHandler();
                this._attachCursorHandlers()
            },
            _createScrollers: function() {
                this._scrollers = {};
                if (this._isDirection(HORIZONTAL))
                    this._createScroller(HORIZONTAL);
                if (this._isDirection(VERTICAL))
                    this._createScroller(VERTICAL);
                this._$element.toggleClass(SCROLLABLE_SCROLLBARS_HIDDEN, !this.option("showScrollbar"))
            },
            _createScroller: function(direction) {
                this._scrollers[direction] = new Scroller(this._scrollerOptions(direction))
            },
            _scrollerOptions: function(direction) {
                return {
                        direction: direction,
                        $content: this._$content,
                        $container: this._$container,
                        $element: this._$element,
                        scrollByContent: this.option("scrollByContent"),
                        scrollByThumb: this.option("scrollByThumb"),
                        scrollbarVisible: this.option("showScrollbar"),
                        bounceEnabled: this.option("bounceEnabled"),
                        inertiaEnabled: this.option("inertiaEnabled")
                    }
            },
            handleInit: function(e) {
                this._supressDirections(e);
                this._eventForUserAction = e;
                this._handleEvent("Init", e).done(this._stopAction)
            },
            _supressDirections: function(e) {
                if (isWheelEvent(e.originalEvent)) {
                    this._prepareDirections(true);
                    return
                }
                this._prepareDirections();
                this._eachScroller(function(scroller, direction) {
                    var isValid = scroller._validateEvent(e);
                    this._validDirections[direction] = isValid
                })
            },
            _prepareDirections: function(value) {
                value = value || false;
                this._validDirections = {};
                this._validDirections[HORIZONTAL] = value;
                this._validDirections[VERTICAL] = value
            },
            _eachScroller: function(callback) {
                callback = $.proxy(callback, this);
                $.each(this._scrollers, function(direction, scroller) {
                    callback(scroller, direction)
                })
            },
            handleStart: function(e) {
                this._saveActive();
                this._handleEvent("Start").done(this._startAction)
            },
            _saveActive: function() {
                activeScrollable = this
            },
            _resetActive: function() {
                activeScrollable = null
            },
            _validateDirection: function(delta) {
                var result = false;
                this._eachScroller(function(scroller) {
                    result = result || scroller._validateDirection(delta)
                });
                return result
            },
            handleMove: function(e) {
                if (this._isLocked()) {
                    e.cancel = true;
                    this._resetActive();
                    return
                }
                e.preventDefault && e.preventDefault();
                this._adjustDistance(e.delta);
                this._eventForUserAction = e;
                this._handleEvent("Move", e.delta)
            },
            _adjustDistance: function(distance) {
                distance.x *= this._validDirections[HORIZONTAL];
                distance.y *= this._validDirections[VERTICAL]
            },
            handleEnd: function(e) {
                this._resetActive();
                this._refreshCursorState(e.originalEvent && e.originalEvent.target);
                this._adjustDistance(e.velocity);
                this._eventForUserAction = e;
                return this._handleEvent("End", e.velocity).done(this._endAction)
            },
            handleCancel: function(e) {
                this._resetActive();
                this._eventForUserAction = e;
                return this._handleEvent("End", {
                        x: 0,
                        y: 0
                    })
            },
            handleStop: function() {
                this._resetActive();
                this._handleEvent("Stop")
            },
            handleScroll: function() {
                var distance = {
                        left: this._$container.scrollLeft(),
                        top: this._$container.scrollTop()
                    };
                this._$container.scrollLeft(-distance.left);
                this._$container.scrollTop(-distance.top);
                this.scrollBy(distance)
            },
            _attachKeyboardHandler: function() {
                this._$element.off("." + SCROLLABLE_SIMULATED_KEYBOARD);
                if (!this.option("disabled") && this.option("useKeyboard"))
                    this._$element.on(events.addNamespace("keydown", SCROLLABLE_SIMULATED_KEYBOARD), $.proxy(this._handleKeyDown, this))
            },
            _handleKeyDown: function(e) {
                if (!this._$container.is(document.activeElement))
                    return;
                var handled = true;
                switch (e.keyCode) {
                    case KEY_CODES.DOWN:
                        this._scrollByLine({y: 1});
                        break;
                    case KEY_CODES.UP:
                        this._scrollByLine({y: -1});
                        break;
                    case KEY_CODES.RIGHT:
                        this._scrollByLine({x: 1});
                        break;
                    case KEY_CODES.LEFT:
                        this._scrollByLine({x: -1});
                        break;
                    case KEY_CODES.PAGE_DOWN:
                        this._scrollByPage(1);
                        break;
                    case KEY_CODES.PAGE_UP:
                        this._scrollByPage(-1);
                        break;
                    case KEY_CODES.HOME:
                        this._scrollToHome();
                        break;
                    case KEY_CODES.END:
                        this._scrollToEnd();
                        break;
                    default:
                        handled = false;
                        break
                }
                if (handled) {
                    e.stopPropagation();
                    e.preventDefault()
                }
            },
            _scrollByLine: function(lines) {
                this.scrollBy({
                    top: (lines.y || 0) * -SCROLL_LINE_HEIGHT,
                    left: (lines.x || 0) * -SCROLL_LINE_HEIGHT
                })
            },
            _scrollByPage: function(page) {
                var prop = this._wheelProp(),
                    dimension = this._dimensionByProp(prop);
                var distance = {};
                distance[prop] = page * -this._$container[dimension]();
                this.scrollBy(distance)
            },
            _dimensionByProp: function(prop) {
                return prop === "left" ? "width" : "height"
            },
            _scrollToHome: function() {
                var prop = this._wheelProp();
                var distance = {};
                distance[prop] = 0;
                this._component.scrollTo(distance)
            },
            _scrollToEnd: function() {
                var prop = this._wheelProp(),
                    dimension = this._dimensionByProp(prop);
                var distance = {};
                distance[prop] = this._$content[dimension]() - this._$container[dimension]();
                this._component.scrollTo(distance)
            },
            createActions: function() {
                this._startAction = this._createActionHandler("startAction");
                this._stopAction = this._createActionHandler("stopAction");
                this._endAction = this._createActionHandler("endAction");
                this._updateAction = this._createActionHandler("updateAction");
                this._createScrollerActions()
            },
            _createScrollerActions: function() {
                this._handleEvent("CreateActions", {
                    scrollAction: this._createActionHandler("scrollAction"),
                    bounceAction: this._createActionHandler("bounceAction")
                })
            },
            _createActionHandler: function(optionName) {
                var that = this,
                    actionHandler = that._createActionByOption(optionName, {excludeValidators: ["gesture"]});
                return function() {
                        actionHandler($.extend(that._createActionArgs(), arguments))
                    }
            },
            _createActionArgs: function() {
                var scrollerX = this._scrollers[HORIZONTAL],
                    scrollerY = this._scrollers[VERTICAL];
                return {
                        jQueryEvent: this._eventForUserAction,
                        scrollOffset: {
                            top: scrollerY && -scrollerY._location,
                            left: scrollerX && -scrollerX._location
                        },
                        reachedLeft: scrollerX && scrollerX._reachedMax(),
                        reachedRight: scrollerX && scrollerX._reachedMin(),
                        reachedTop: scrollerY && scrollerY._reachedMax(),
                        reachedBottom: scrollerY && scrollerY._reachedMin()
                    }
            },
            _handleEvent: function(eventName) {
                var args = $.makeArray(arguments).slice(1),
                    deferreds = $.map(this._scrollers, function(scroller) {
                        return scroller["_handle" + eventName].apply(scroller, args)
                    });
                return $.when.apply($, deferreds).promise()
            },
            location: function() {
                return DX.translator.locate(this._$content)
            },
            disabledChanged: function() {
                this._attachCursorHandlers()
            },
            _attachCursorHandlers: function() {
                this._$element.off("." + SCROLLABLE_SIMULATED_CURSOR);
                if (!this.option("disabled") && this._isHoverMode())
                    this._$element.on(events.addNamespace("mouseenter", SCROLLABLE_SIMULATED_CURSOR), $.proxy(this._handleCursorEnter, this)).on(events.addNamespace("mouseleave", SCROLLABLE_SIMULATED_CURSOR), $.proxy(this._handleCursorLeave, this))
            },
            _isHoverMode: function() {
                return this.option("showScrollbar") === "onHover"
            },
            _handleCursorEnter: function(e) {
                e = e || {};
                e.originalEvent = e.originalEvent || {};
                if (activeScrollable || e.originalEvent._hoverHandled)
                    return;
                if (hoveredScrollable)
                    hoveredScrollable._handleCursorLeave();
                hoveredScrollable = this;
                this._handleEvent("CursorEnter");
                e.originalEvent._hoverHandled = true
            },
            _handleCursorLeave: function(e) {
                if (hoveredScrollable !== this || activeScrollable === hoveredScrollable)
                    return;
                this._handleEvent("CursorLeave");
                hoveredScrollable = null;
                this._refreshCursorState(e && e.relatedTarget)
            },
            _refreshCursorState: function(target) {
                if (!this._isHoverMode() && (!target || activeScrollable))
                    return;
                var $target = $(target);
                var $scrollable = $target.closest("." + SCROLLABLE_SIMULATED_CLASS + ":not(.dx-state-disabled)");
                var targetScrollable = $scrollable.length && $scrollable.data(SCROLLABLE_STRATEGY);
                if (hoveredScrollable && hoveredScrollable !== targetScrollable)
                    hoveredScrollable._handleCursorLeave();
                if (targetScrollable)
                    targetScrollable._handleCursorEnter()
            },
            update: function() {
                return this._handleEvent("Update").done(this._updateAction)
            },
            _allowedDirections: function() {
                return {
                        vertical: this._isDirection(VERTICAL) && this._scrollers[VERTICAL]._minOffset < 0,
                        horizontal: this._isDirection(HORIZONTAL) && this._scrollers[HORIZONTAL]._minOffset < 0
                    }
            },
            scrollBy: function(distance) {
                this._prepareDirections(true);
                this._handleEvent("Start").done(this._startAction);
                this._handleEvent("Move", {
                    x: distance.left,
                    y: distance.top
                });
                this._handleEvent("End", {
                    x: 0,
                    y: 0
                }).done(this._endAction)
            },
            validate: function(e) {
                if (this.option("disabled"))
                    return false;
                this.update();
                if (this.option("bounceEnabled"))
                    return true;
                return isWheelEvent(e) ? this._validateWheel(e) : this._validateMove()
            },
            _validateWheel: function(e) {
                var scroller = this._scrollers[this._wheelDirection()];
                var reachedMin = scroller._reachedMin();
                var reachedMax = scroller._reachedMax();
                var contentGreaterThanContainer = !reachedMin || !reachedMax;
                var locatedNotAtBound = !reachedMin && !reachedMax;
                var scrollFromMin = reachedMin && e.delta > 0;
                var scrollFromMax = reachedMax && e.delta < 0;
                return contentGreaterThanContainer && (locatedNotAtBound || scrollFromMin || scrollFromMax)
            },
            _validateMove: function() {
                return this._allowedDirection()
            },
            getDirection: function(e) {
                return isWheelEvent(e) ? this._wheelDirection() : this._allowedDirection()
            },
            _wheelProp: function() {
                return this._wheelDirection() === HORIZONTAL ? "left" : "top"
            },
            _wheelDirection: function() {
                switch (this.option("direction")) {
                    case HORIZONTAL:
                        return HORIZONTAL;
                    case VERTICAL:
                        return VERTICAL;
                    default:
                        return this._scrollers[VERTICAL]._containerToContentRatio() >= 1 ? HORIZONTAL : VERTICAL
                }
            },
            dispose: function() {
                if (activeScrollable === this)
                    activeScrollable = null;
                if (hoveredScrollable === this)
                    hoveredScrollable = null;
                this._handleEvent("Dispose");
                this._detachEventHandlers();
                this._$element.removeClass(SCROLLABLE_SIMULATED_CLASS);
                this._eventForUserAction = null;
                clearTimeout(this._gestureEndTimer)
            },
            _detachEventHandlers: function() {
                this._$element.off("." + SCROLLABLE_SIMULATED_CURSOR);
                this._$container.off("." + SCROLLABLE_SIMULATED_KEYBOARD)
            }
        });
        ui.dxScrollable.__internals = $.extend(ui.dxScrollable.__internals || {}, {
            ACCELERATION: ACCELERATION,
            MIN_VELOCITY_LIMIT: MIN_VELOCITY_LIMIT,
            FRAME_DURATION: FRAME_DURATION,
            SCROLL_LINE_HEIGHT: SCROLL_LINE_HEIGHT
        })
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollView.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var SCROLLVIEW_CLASS = "dx-scrollview",
            SCROLLVIEW_CONTENT_CLASS = SCROLLVIEW_CLASS + "-content",
            SCROLLVIEW_TOP_POCKET_CLASS = SCROLLVIEW_CLASS + "-top-pocket",
            SCROLLVIEW_BOTTOM_POCKET_CLASS = SCROLLVIEW_CLASS + "-bottom-pocket",
            SCROLLVIEW_PULLDOWN_CLASS = SCROLLVIEW_CLASS + "-pull-down",
            SCROLLVIEW_PULLDOWN_IMAGE_CLASS = SCROLLVIEW_PULLDOWN_CLASS + "-image",
            SCROLLVIEW_PULLDOWN_INDICATOR_CLASS = SCROLLVIEW_PULLDOWN_CLASS + "-indicator",
            SCROLLVIEW_PULLDOWN_TEXT_CLASS = SCROLLVIEW_PULLDOWN_CLASS + "-text",
            SCROLLVIEW_REACHBOTTOM_CLASS = SCROLLVIEW_CLASS + "-scrollbottom",
            SCROLLVIEW_REACHBOTTOM_INDICATOR_CLASS = SCROLLVIEW_REACHBOTTOM_CLASS + "-indicator",
            SCROLLVIEW_REACHBOTTOM_TEXT_CLASS = SCROLLVIEW_REACHBOTTOM_CLASS + "-text",
            SCROLLVIEW_LOADPANEL = SCROLLVIEW_CLASS + "-loadpanel";
        DX.registerComponent("dxScrollView", ui.dxScrollable.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    pullingDownText: Globalize.localize("dxScrollView-pullingDownText"),
                    pulledDownText: Globalize.localize("dxScrollView-pulledDownText"),
                    refreshingText: Globalize.localize("dxScrollView-refreshingText"),
                    reachBottomText: Globalize.localize("dxScrollView-reachBottomText"),
                    pullDownAction: null,
                    reachBottomAction: null,
                    refreshStrategy: "pullDown"
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function(device) {
                                return DevExpress.devices.real().platform === "android"
                            },
                            options: {refreshStrategy: "swipeDown"}
                        }, {
                            device: function(device) {
                                return DevExpress.devices.real().platform === "win8"
                            },
                            options: {refreshStrategy: "slideDown"}
                        }])
            },
            _init: function() {
                this.callBase();
                this._loadingIndicatorEnabled = true
            },
            _initMarkup: function() {
                this.callBase();
                this._element().addClass(SCROLLVIEW_CLASS);
                this._initContent();
                this._initTopPocket();
                this._initBottomPocket();
                this._initLoadPanel()
            },
            _initContent: function() {
                var $content = $("<div>").addClass(SCROLLVIEW_CONTENT_CLASS);
                this._$content.wrapInner($content)
            },
            _initTopPocket: function() {
                var $topPocket = this._$topPocket = $("<div>").addClass(SCROLLVIEW_TOP_POCKET_CLASS),
                    $pullDown = this._$pullDown = $("<div>").addClass(SCROLLVIEW_PULLDOWN_CLASS);
                $topPocket.append($pullDown);
                this._$content.prepend($topPocket)
            },
            _initBottomPocket: function() {
                var $bottomPocket = this._$bottomPocket = $("<div>").addClass(SCROLLVIEW_BOTTOM_POCKET_CLASS),
                    $reachBottom = this._$reachBottom = $("<div>").addClass(SCROLLVIEW_REACHBOTTOM_CLASS),
                    $loadContainer = $("<div>").addClass(SCROLLVIEW_REACHBOTTOM_INDICATOR_CLASS),
                    $loadIndicator = $("<div>").dxLoadIndicator(),
                    $text = this._$reachBottomText = $("<div>").addClass(SCROLLVIEW_REACHBOTTOM_TEXT_CLASS);
                this._updateReachBottomText();
                $reachBottom.append($loadContainer.append($loadIndicator)).append($text);
                $bottomPocket.append($reachBottom);
                this._$content.append($bottomPocket)
            },
            _initLoadPanel: function() {
                this._loadPanel = $("<div>").addClass(SCROLLVIEW_LOADPANEL).appendTo(this._element()).dxLoadPanel({
                    shading: false,
                    delay: 400,
                    position: {of: this._element()}
                }).dxLoadPanel("instance")
            },
            _updateReachBottomText: function() {
                this._$reachBottomText.text(this.option("reachBottomText"))
            },
            _createStrategy: function() {
                var strategyName = this.option("useNative") ? this.option("refreshStrategy") : "simulated";
                var strategyClass = ui.scrollViewRefreshStrategies[strategyName];
                if (!strategyClass)
                    throw Error("Unknown dxScrollView refresh strategy " + this.option("refreshStrategy"));
                this._strategy = new strategyClass(this);
                this._strategy.pullDownCallbacks.add($.proxy(this._handlePullDown, this));
                this._strategy.releaseCallbacks.add($.proxy(this._handleRelease, this));
                this._strategy.reachBottomCallbacks.add($.proxy(this._handleReachBottom, this))
            },
            _createActions: function() {
                this.callBase();
                this._pullDownAction = this._createActionByOption("pullDownAction", {excludeValidators: ["gesture"]});
                this._reachBottomAction = this._createActionByOption("reachBottomAction", {excludeValidators: ["gesture"]});
                this._pullDownEnable(!!this.option("pullDownAction") && !DX.designMode);
                this._reachBottomEnable(!!this.option("reachBottomAction") && !DX.designMode)
            },
            _pullDownEnable: function(enabled) {
                this._$pullDown.toggle(enabled);
                this._strategy.pullDownEnable(enabled)
            },
            _reachBottomEnable: function(enabled) {
                this._$reachBottom.toggle(enabled);
                this._strategy.reachBottomEnable(enabled)
            },
            _handlePullDown: function() {
                this._loadingIndicator(false);
                this._pullDownLoading()
            },
            _loadingIndicator: function(value) {
                if (arguments.length < 1)
                    return this._loadingIndicatorEnabled;
                this._loadingIndicatorEnabled = value
            },
            _pullDownLoading: function() {
                this.startLoading();
                this._pullDownAction()
            },
            _handleReachBottom: function() {
                this._loadingIndicator(false);
                this._reachBottomLoading()
            },
            _reachBottomLoading: function() {
                this.startLoading();
                this._reachBottomAction()
            },
            _handleRelease: function() {
                this.finishLoading();
                this._loadingIndicator(true)
            },
            _optionChanged: function(optionName, optionValue) {
                switch (optionName) {
                    case"pullDownAction":
                    case"reachBottomAction":
                        this._createActions();
                        break;
                    case"pullingDownText":
                    case"pulledDownText":
                    case"refreshingText":
                    case"refreshStrategy":
                        this._invalidate();
                        break;
                    case"reachBottomText":
                        this._updateReachBottomText();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            content: function() {
                return this._$content.children().eq(1)
            },
            release: function(preventReachBottom) {
                if (preventReachBottom !== undefined)
                    this.toggleLoading(!preventReachBottom);
                return this._strategy.release()
            },
            toggleLoading: function(showOrHide) {
                this._reachBottomEnable(showOrHide)
            },
            isFull: function() {
                return this.content().height() >= this._$container.height()
            },
            refresh: function() {
                if (!this.option("pullDownAction"))
                    return;
                this._strategy.pendingRelease();
                this._pullDownLoading()
            },
            startLoading: function() {
                if (this._loadingIndicator() && this._element().is(":visible"))
                    this._loadPanel.show();
                this._lock()
            },
            finishLoading: function() {
                if (this._loadingIndicator())
                    this._loadPanel.hide();
                this._unlock()
            },
            _dispose: function() {
                this.callBase();
                if (this._loadPanel)
                    this._loadPanel._element().remove()
            }
        }));
        ui.scrollViewRefreshStrategies = {}
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollView.native.pullDown.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            math = Math;
        var SCROLLVIEW_PULLDOWN_REFRESHING_CLASS = "dx-scrollview-pull-down-loading",
            SCROLLVIEW_PULLDOWN_READY_CLASS = "dx-scrollview-pull-down-ready",
            SCROLLVIEW_PULLDOWN_IMAGE_CLASS = "dx-scrollview-pull-down-image",
            SCROLLVIEW_PULLDOWN_INDICATOR_CLASS = "dx-scrollview-pull-down-indicator",
            SCROLLVIEW_PULLDOWN_TEXT_CLASS = "dx-scrollview-pull-down-text",
            STATE_RELEASED = 0,
            STATE_READY = 1,
            STATE_REFRESHING = 2,
            STATE_LOADING = 3;
        var PullDownNativeScrollViewStrategy = ui.NativeScrollableStrategy.inherit({
                _init: function(scrollView) {
                    this.callBase(scrollView);
                    this._$topPocket = scrollView._$topPocket;
                    this._$pullDown = scrollView._$pullDown;
                    this._$bottomPocket = scrollView._$bottomPocket;
                    this._$refreshingText = scrollView._$refreshingText;
                    this._$scrollViewContent = scrollView.content();
                    this._initCallbacks()
                },
                _initCallbacks: function() {
                    this.pullDownCallbacks = $.Callbacks();
                    this.releaseCallbacks = $.Callbacks();
                    this.reachBottomCallbacks = $.Callbacks()
                },
                render: function() {
                    this.callBase();
                    this._renderPullDown();
                    this._releaseState()
                },
                _renderPullDown: function() {
                    var $image = $("<div>").addClass(SCROLLVIEW_PULLDOWN_IMAGE_CLASS),
                        $loadContainer = $("<div>").addClass(SCROLLVIEW_PULLDOWN_INDICATOR_CLASS),
                        $loadIndicator = $("<div>").dxLoadIndicator(),
                        $text = this._$pullDownText = $("<div>").addClass(SCROLLVIEW_PULLDOWN_TEXT_CLASS);
                    this._$pullingDownText = $("<div>").text(this.option("pullingDownText")).appendTo($text);
                    this._$pulledDownText = $("<div>").text(this.option("pulledDownText")).appendTo($text);
                    this._$refreshingText = $("<div>").text(this.option("refreshingText")).appendTo($text);
                    this._$pullDown.empty().append($image).append($loadContainer.append($loadIndicator)).append($text)
                },
                _releaseState: function() {
                    this._state = STATE_RELEASED;
                    this._refreshPullDownText()
                },
                _refreshPullDownText: function() {
                    this._$pullingDownText.css("opacity", this._state === STATE_RELEASED ? 1 : 0);
                    this._$pulledDownText.css("opacity", this._state === STATE_READY ? 1 : 0);
                    this._$refreshingText.css("opacity", this._state === STATE_REFRESHING ? 1 : 0)
                },
                update: function() {
                    this.callBase();
                    this._setTopPocketOffset()
                },
                _updateDimensions: function() {
                    this.callBase();
                    this._topPocketSize = this._$topPocket.height();
                    this._bottomPocketSize = this._$bottomPocket.height();
                    this._scrollOffset = this._$container.height() - this._$content.height()
                },
                _setTopPocketOffset: function() {
                    this._$topPocket.css({top: -this._topPocketSize})
                },
                handleEnd: function() {
                    this._complete()
                },
                handleStop: function() {
                    this._complete()
                },
                _complete: function() {
                    if (this._state === STATE_READY) {
                        this._setPullDownOffset(this._topPocketSize);
                        clearTimeout(this._pullDownRefreshTimeout);
                        this._pullDownRefreshTimeout = setTimeout($.proxy(function() {
                            this._pullDownRefreshing()
                        }, this), 400)
                    }
                },
                _setPullDownOffset: function(offset) {
                    DX.translator.move(this._$topPocket, {top: offset});
                    DX.translator.move(this._$scrollViewContent, {top: offset})
                },
                handleScroll: function(e) {
                    this.callBase(e);
                    if (this._state === STATE_REFRESHING)
                        return;
                    this._location = this.location().top;
                    if (this._isPullDown())
                        this._pullDownReady();
                    else if (this._isReachBottom())
                        this._reachBottom();
                    else
                        this._stateReleased()
                },
                _isPullDown: function() {
                    return this._pullDownEnabled && this._location >= this._topPocketSize
                },
                _isReachBottom: function() {
                    return this._reachBottomEnabled && this._location <= this._scrollOffset + this._bottomPocketSize
                },
                _reachBottom: function() {
                    if (this._state === STATE_LOADING)
                        return;
                    this._state = STATE_LOADING;
                    this.reachBottomCallbacks.fire()
                },
                _pullDownReady: function() {
                    if (this._state === STATE_READY)
                        return;
                    this._state = STATE_READY;
                    this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
                    this._refreshPullDownText()
                },
                _stateReleased: function() {
                    if (this._state === STATE_RELEASED)
                        return;
                    this._$pullDown.removeClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
                    this._releaseState()
                },
                _pullDownRefreshing: function() {
                    if (this._state === STATE_REFRESHING)
                        return;
                    this._state = STATE_REFRESHING;
                    this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
                    this._refreshPullDownText();
                    this.pullDownCallbacks.fire()
                },
                pullDownEnable: function(enabled) {
                    this._pullDownEnabled = enabled
                },
                reachBottomEnable: function(enabled) {
                    this._reachBottomEnabled = enabled
                },
                pendingRelease: function() {
                    this._state = STATE_READY
                },
                release: function() {
                    var deferred = $.Deferred();
                    this._updateDimensions();
                    clearTimeout(this._releaseTimeout);
                    this._releaseTimeout = setTimeout($.proxy(function() {
                        this._setPullDownOffset(0);
                        this._stateReleased();
                        this.releaseCallbacks.fire();
                        this._updateAction();
                        deferred.resolve()
                    }, this), 400);
                    return deferred.promise()
                },
                dispose: function() {
                    clearTimeout(this._pullDownRefreshTimeout);
                    clearTimeout(this._releaseTimeout);
                    this.callBase()
                }
            });
        ui.scrollViewRefreshStrategies.pullDown = PullDownNativeScrollViewStrategy
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollView.native.swipeDown.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            math = Math;
        var SCROLLVIEW_PULLDOWN_REFRESHING_CLASS = "dx-scrollview-pull-down-loading",
            SCROLLVIEW_OBSOLETE_ANDROID_CLASS = "dx-scrollview-obsolete-android-browser",
            PULLDOWN_HEIGHT = 160,
            STATE_RELEASED = 0,
            STATE_READY = 1,
            STATE_REFRESHING = 2,
            STATE_LOADING = 3,
            STATE_TOUCHED = 4,
            STATE_PULLED = 5;
        var SwipeDownNativeScrollViewStrategy = ui.NativeScrollableStrategy.inherit({
                _init: function(scrollView) {
                    this.callBase(scrollView);
                    this._$topPocket = scrollView._$topPocket;
                    this._$bottomPocket = scrollView._$bottomPocket;
                    this._$pullDown = scrollView._$pullDown;
                    this._$scrollViewContent = scrollView.content();
                    this._initCallbacks();
                    this._releaseState();
                    this._location = 0
                },
                _initCallbacks: function() {
                    this.pullDownCallbacks = $.Callbacks();
                    this.releaseCallbacks = $.Callbacks();
                    this.reachBottomCallbacks = $.Callbacks()
                },
                render: function() {
                    this.callBase();
                    this._renderPullDown()
                },
                _renderPullDown: function() {
                    this._$pullDown.empty().append($("<div class='dx-scrollview-pulldown-pointer1'>")).append($("<div class='dx-scrollview-pulldown-pointer2'>")).append($("<div class='dx-scrollview-pulldown-pointer3'>")).append($("<div class='dx-scrollview-pulldown-pointer4'>"))
                },
                _releaseState: function() {
                    this._state = STATE_RELEASED;
                    this._$pullDown.css({
                        width: "0%",
                        opacity: 0
                    });
                    this._updateDimensions()
                },
                _updateDimensions: function() {
                    this.callBase();
                    this._topPocketSize = this._$topPocket.height();
                    this._bottomPocketSize = this._$bottomPocket.height();
                    this._scrollOffset = this._$container.height() - this._$content.height()
                },
                handleInit: function(e) {
                    this.callBase(e);
                    if (this._state === STATE_RELEASED && this._location === 0) {
                        this._startClientY = events.eventData(e.originalEvent).y;
                        this._state = STATE_TOUCHED
                    }
                },
                handleMove: function(e) {
                    this.callBase(e);
                    this._deltaY = events.eventData(e.originalEvent).y - this._startClientY;
                    if (this._state === STATE_TOUCHED)
                        if (this._pullDownEnabled && this._deltaY > 0) {
                            e.preventDefault();
                            this._state = STATE_PULLED
                        }
                        else
                            this._complete();
                    if (this._state === STATE_PULLED) {
                        if (this._deltaY < 0) {
                            this._complete();
                            return
                        }
                        this._$pullDown.css({
                            opacity: 1,
                            width: math.min(math.abs(this._deltaY * 100 / PULLDOWN_HEIGHT), 100) + "%"
                        });
                        if (this._isPullDown())
                            this._pullDownRefreshing()
                    }
                },
                _isPullDown: function() {
                    return this._pullDownEnabled && this._deltaY >= PULLDOWN_HEIGHT
                },
                handleEnd: function() {
                    this._complete()
                },
                handleStop: function() {
                    this._complete()
                },
                _complete: function() {
                    if (this._state === STATE_TOUCHED || this._state === STATE_PULLED)
                        this._releaseState()
                },
                handleScroll: function(e) {
                    this.callBase(e);
                    if (this._state === STATE_REFRESHING)
                        return;
                    var currentLocation = this.location().top,
                        scrollDelta = this._location - currentLocation;
                    this._location = currentLocation;
                    if (scrollDelta > 0 && this._isReachBottom())
                        this._reachBottom();
                    else
                        this._stateReleased()
                },
                _isReachBottom: function() {
                    return this._reachBottomEnabled && this._location <= this._scrollOffset + this._bottomPocketSize
                },
                _reachBottom: function() {
                    this.reachBottomCallbacks.fire()
                },
                _stateReleased: function() {
                    if (this._state === STATE_RELEASED)
                        return;
                    this._$pullDown.removeClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS);
                    this._releaseState()
                },
                _pullDownRefreshing: function() {
                    if (this._state === STATE_REFRESHING)
                        return;
                    this._state = STATE_REFRESHING;
                    clearTimeout(this._pullDownRefreshTimeout);
                    this._pullDownRefreshTimeout = setTimeout($.proxy(function() {
                        this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS);
                        this.pullDownCallbacks.fire()
                    }, this), 400)
                },
                pullDownEnable: function(enabled) {
                    this._$topPocket.toggle(enabled);
                    this._pullDownEnabled = enabled
                },
                reachBottomEnable: function(enabled) {
                    this._reachBottomEnabled = enabled
                },
                pendingRelease: function() {
                    this._state = STATE_READY
                },
                release: function() {
                    var deferred = $.Deferred();
                    this._updateDimensions();
                    clearTimeout(this._releaseTimeout);
                    this._releaseTimeout = setTimeout($.proxy(function() {
                        this._stateReleased();
                        this.releaseCallbacks.fire();
                        this._updateAction();
                        deferred.resolve()
                    }, this), 800);
                    return deferred.promise()
                },
                dispose: function() {
                    clearTimeout(this._pullDownRefreshTimeout);
                    clearTimeout(this._releaseTimeout);
                    this.callBase()
                }
            });
        ui.scrollViewRefreshStrategies.swipeDown = SwipeDownNativeScrollViewStrategy
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollView.native.slideDown.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var DX_SLIDE_DOWN_NATIVE_SCROLLVIEW_STRATEGY = "dxSlideDownNativeScrollViewStrategy",
            STATE_RELEASED = 0,
            STATE_READY = 1,
            STATE_LOADING = 2,
            LOADING_HEIGHT = 80;
        var SlideDownNativeScrollViewStrategy = ui.NativeScrollableStrategy.inherit({
                _init: function(scrollView) {
                    this.callBase(scrollView);
                    this._$topPocket = scrollView._$topPocket;
                    this._$bottomPocket = scrollView._$bottomPocket;
                    this._initCallbacks()
                },
                _initCallbacks: function() {
                    this.pullDownCallbacks = $.Callbacks();
                    this.releaseCallbacks = $.Callbacks();
                    this.reachBottomCallbacks = $.Callbacks()
                },
                render: function() {
                    this.callBase();
                    this._renderPullDown();
                    this._renderBottom();
                    this._releaseState();
                    this._updateDimensions()
                },
                _renderPullDown: function() {
                    this._$topPocket.empty()
                },
                _renderBottom: function() {
                    this._$bottomPocket.empty().append("<progress>")
                },
                _releaseState: function() {
                    if (this._state === STATE_RELEASED)
                        return;
                    this._state = STATE_RELEASED
                },
                _updateDimensions: function() {
                    this._scrollOffset = this._$container.prop("scrollHeight") - this._$container.prop("clientHeight");
                    this._containerSize = {
                        height: this._$container.prop("clientHeight"),
                        width: this._$container.prop("clientWidth")
                    };
                    this._contentSize = this._componentContentSize = {
                        height: this._$container.prop("scrollHeight"),
                        width: this._$container.prop("scrollWidth")
                    }
                },
                handleScroll: function(e) {
                    this.callBase(e);
                    if (this._isReachBottom(this._lastLocation.top))
                        this._reachBottom()
                },
                _isReachBottom: function(location) {
                    this._scrollContent = this._$container.prop("scrollHeight") - this._$container.prop("clientHeight");
                    return this._reachBottomEnabled && location < -this._scrollContent + LOADING_HEIGHT
                },
                _reachBottom: function() {
                    if (this._state === STATE_LOADING)
                        return;
                    this._state = STATE_LOADING;
                    this.reachBottomCallbacks.fire()
                },
                pullDownEnable: function(enabled) {
                    this._pullDownEnabled = enabled
                },
                reachBottomEnable: function(enabled) {
                    this._reachBottomEnabled = enabled;
                    this._$bottomPocket.toggle(enabled)
                },
                pendingRelease: function() {
                    this._state = STATE_READY
                },
                release: function() {
                    var deferred = $.Deferred();
                    this._state = STATE_RELEASED;
                    this.releaseCallbacks.fire();
                    this.update();
                    return deferred.resolve().promise()
                }
            });
        ui.scrollViewRefreshStrategies.slideDown = SlideDownNativeScrollViewStrategy
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.scrollView.simulated.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            math = Math;
        var SCROLLVIEW_PULLDOWN_REFRESHING_CLASS = "dx-scrollview-pull-down-loading",
            SCROLLVIEW_PULLDOWN_READY_CLASS = "dx-scrollview-pull-down-ready",
            SCROLLVIEW_PULLDOWN_IMAGE_CLASS = "dx-scrollview-pull-down-image",
            SCROLLVIEW_PULLDOWN_INDICATOR_CLASS = "dx-scrollview-pull-down-indicator",
            SCROLLVIEW_PULLDOWN_TEXT_CLASS = "dx-scrollview-pull-down-text",
            STATE_RELEASED = 0,
            STATE_READY = 1,
            STATE_REFRESHING = 2,
            STATE_LOADING = 3;
        var ScrollViewScroller = ui.ScrollViewScroller = ui.Scroller.inherit({
                ctor: function() {
                    this.callBase.apply(this, arguments);
                    this._initCallbacks();
                    this._releaseState()
                },
                _releaseState: function() {
                    this._state = STATE_RELEASED;
                    this._refreshPullDownText()
                },
                _refreshPullDownText: function() {
                    this._$pullingDownText.css("opacity", this._state === STATE_RELEASED ? 1 : 0);
                    this._$pulledDownText.css("opacity", this._state === STATE_READY ? 1 : 0);
                    this._$refreshingText.css("opacity", this._state === STATE_REFRESHING ? 1 : 0)
                },
                _initCallbacks: function() {
                    this.pullDownCallbacks = $.Callbacks();
                    this.releaseCallbacks = $.Callbacks();
                    this.reachBottomCallbacks = $.Callbacks()
                },
                _updateBounds: function() {
                    var considerPockets = this._direction !== "horizontal";
                    this._topPocketSize = considerPockets ? this._$topPocket[this._dimension]() : 0;
                    this._bottomPocketSize = considerPockets ? this._$bottomPocket[this._dimension]() : 0;
                    this._updateOffsets()
                },
                _updateOffsets: function() {
                    this._minOffset = math.min(this._containerSize() - this._contentSize() + this._bottomPocketSize, -this._topPocketSize);
                    this._maxOffset = -this._topPocketSize;
                    this._bottomBound = this._minOffset - this._bottomPocketSize
                },
                _updateScrollbar: function() {
                    this._scrollbar.option({
                        containerSize: this._containerSize(),
                        contentSize: this._contentSize() - this._topPocketSize - this._bottomPocketSize
                    })
                },
                _moveContent: function() {
                    this.callBase();
                    if (this._isPullDown())
                        this._pullDownReady();
                    else if (this._isReachBottom())
                        this._reachBottomReady();
                    else if (this._state !== STATE_RELEASED)
                        this._stateReleased()
                },
                _moveScrollbar: function() {
                    this._scrollbar.moveTo(this._topPocketSize + this._location)
                },
                _isPullDown: function() {
                    return this._pullDownEnabled && this._location >= 0
                },
                _isReachBottom: function() {
                    return this._reachBottomEnabled && this._location <= this._bottomBound
                },
                _scrollComplete: function() {
                    if (this._inBounds() && this._state === STATE_READY)
                        this._pullDownRefreshing();
                    else if (this._inBounds() && this._state === STATE_LOADING)
                        this._reachBottomLoading();
                    else
                        this.callBase()
                },
                _reachBottomReady: function() {
                    if (this._state === STATE_LOADING)
                        return;
                    this._state = STATE_LOADING;
                    this._minOffset = math.min(this._containerSize() - this._contentSize(), 0)
                },
                _reachBottomLoading: function() {
                    this.reachBottomCallbacks.fire()
                },
                _pullDownReady: function() {
                    if (this._state === STATE_READY)
                        return;
                    this._state = STATE_READY;
                    this._maxOffset = 0;
                    this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
                    this._refreshPullDownText()
                },
                _stateReleased: function() {
                    if (this._state === STATE_RELEASED)
                        return;
                    this._releaseState();
                    this._updateOffsets();
                    this._$pullDown.removeClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
                    this.releaseCallbacks.fire()
                },
                _pullDownRefreshing: function() {
                    if (this._state === STATE_REFRESHING)
                        return;
                    this._state = STATE_REFRESHING;
                    this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
                    this._refreshPullDownText();
                    this.pullDownCallbacks.fire()
                },
                _handleRelease: function() {
                    if (this._state === STATE_RELEASED)
                        this._moveToBounds();
                    this._update();
                    return DX.utils.executeAsync($.proxy(this._release, this))
                },
                _release: function() {
                    this._stateReleased();
                    this._scrollComplete()
                },
                _handleReachBottomEnabling: function(enabled) {
                    if (this._reachBottomEnabled === enabled)
                        return;
                    this._reachBottomEnabled = enabled;
                    this._updateBounds()
                },
                _handlePullDownEnabling: function(enabled) {
                    if (this._pullDownEnabled === enabled)
                        return;
                    this._pullDownEnabled = enabled;
                    this._considerTopPocketChange();
                    this._handleUpdate()
                },
                _considerTopPocketChange: function() {
                    this._location -= this._$topPocket.height() || -this._topPocketSize;
                    this._move()
                },
                _handlePendingRelease: function() {
                    this._state = STATE_READY
                }
            });
        var SimulatedScrollViewStrategy = ui.SimulatedScrollableStrategy.inherit({
                _init: function(scrollView) {
                    this.callBase(scrollView);
                    this._$pullDown = scrollView._$pullDown;
                    this._$topPocket = scrollView._$topPocket;
                    this._$bottomPocket = scrollView._$bottomPocket;
                    this._initCallbacks()
                },
                _initCallbacks: function() {
                    this.pullDownCallbacks = $.Callbacks();
                    this.releaseCallbacks = $.Callbacks();
                    this.reachBottomCallbacks = $.Callbacks()
                },
                render: function() {
                    this._renderPullDown();
                    this.callBase()
                },
                _renderPullDown: function() {
                    var $image = $("<div>").addClass(SCROLLVIEW_PULLDOWN_IMAGE_CLASS),
                        $loadContainer = $("<div>").addClass(SCROLLVIEW_PULLDOWN_INDICATOR_CLASS),
                        $loadIndicator = $("<div>").dxLoadIndicator(),
                        $text = this._$pullDownText = $("<div>").addClass(SCROLLVIEW_PULLDOWN_TEXT_CLASS);
                    this._$pullingDownText = $("<div>").text(this.option("pullingDownText")).appendTo($text);
                    this._$pulledDownText = $("<div>").text(this.option("pulledDownText")).appendTo($text);
                    this._$refreshingText = $("<div>").text(this.option("refreshingText")).appendTo($text);
                    this._$pullDown.empty().append($image).append($loadContainer.append($loadIndicator)).append($text)
                },
                pullDownEnable: function(enabled) {
                    this._handleEvent("PullDownEnabling", enabled)
                },
                reachBottomEnable: function(enabled) {
                    this._handleEvent("ReachBottomEnabling", enabled)
                },
                _createScroller: function(direction) {
                    var that = this;
                    var scroller = that._scrollers[direction] = new ScrollViewScroller(that._scrollerOptions(direction));
                    scroller.pullDownCallbacks.add(function() {
                        that.pullDownCallbacks.fire()
                    });
                    scroller.releaseCallbacks.add(function() {
                        that.releaseCallbacks.fire()
                    });
                    scroller.reachBottomCallbacks.add(function() {
                        that.reachBottomCallbacks.fire()
                    })
                },
                _scrollerOptions: function(direction) {
                    return $.extend(this.callBase(direction), {
                            $topPocket: this._$topPocket,
                            $bottomPocket: this._$bottomPocket,
                            $pullDown: this._$pullDown,
                            $pullDownText: this._$pullDownText,
                            $pullingDownText: this._$pullingDownText,
                            $pulledDownText: this._$pulledDownText,
                            $refreshingText: this._$refreshingText
                        })
                },
                pendingRelease: function() {
                    this._handleEvent("PendingRelease")
                },
                release: function() {
                    return this._handleEvent("Release").done(this._updateAction)
                }
            });
        ui.scrollViewRefreshStrategies.simulated = SimulatedScrollViewStrategy
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.map.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils,
            winJS = DX.support.winJS,
            wrapToArray = utils.wrapToArray,
            removeDublicates = utils.removeDublicates,
            titleize = DX.inflector.titleize;
        ui.MapProvider = DX.Class.inherit({
            _defaultRouteWeight: function() {
                return 5
            },
            _defaultRouteOpacity: function() {
                return .5
            },
            _defaultRouteColor: function() {
                return "#0000FF"
            },
            ctor: function(map, $container) {
                this._mapWidget = map;
                this._$container = $container
            },
            load: $.noop,
            render: function() {
                var deferred = $.Deferred(),
                    that = this;
                this._renderImpl().done(function() {
                    var markersPromise = that.addMarkers(that._option("markers"));
                    var routesPromise = that.addRoutes(that._option("routes"));
                    $.when(markersPromise, routesPromise).done(function() {
                        deferred.resolve(true)
                    })
                });
                return deferred.promise()
            },
            _renderImpl: DX.abstract,
            updateDimensions: DX.abstract,
            updateMapType: DX.abstract,
            updateCenter: DX.abstract,
            updateZoom: DX.abstract,
            updateControls: DX.abstract,
            updateMarkers: function(markerOptionsToRemove, markerOptionsToAdd) {
                var deferred = $.Deferred(),
                    that = this;
                this.removeMarkers(markerOptionsToRemove).done(function() {
                    that.addMarkers(markerOptionsToAdd).done(function() {
                        deferred.resolve.apply(deferred, arguments)
                    })
                });
                return deferred.promise()
            },
            addMarkers: DX.abstract,
            removeMarkers: DX.abstract,
            adjustViewport: DX.abstract,
            updateRoutes: function(routeOptionsToRemove, routeOptionsToAdd) {
                var deferred = $.Deferred(),
                    that = this;
                this.removeRoutes(routeOptionsToRemove).done(function() {
                    that.addRoutes(routeOptionsToAdd).done(function() {
                        deferred.resolve.apply(deferred, arguments)
                    })
                });
                return deferred.promise()
            },
            addRoutes: DX.abstract,
            removeRoutes: DX.abstract,
            clean: DX.abstract,
            cancelEvents: false,
            map: function() {
                return this._map
            },
            mapRendered: function() {
                return !!this._map
            },
            _option: function(name, value) {
                if (value === undefined)
                    return this._mapWidget.option(name);
                this._mapWidget.setOptionSilent(name, value)
            },
            _keyOption: function(providerName) {
                var key = this._option("key");
                return key[providerName] === undefined ? key : key[providerName]
            },
            _parseTooltipOptions: function(option) {
                return {
                        text: option.text || option,
                        visible: option.isShown || false
                    }
            },
            _addEventNamespace: function(name) {
                return events.addNamespace(name, this._mapWidget.NAME)
            },
            _createAction: function() {
                var mapWidget = this._mapWidget;
                return mapWidget._createAction.apply(mapWidget, arguments)
            },
            _fireAction: function(name, actionArguments) {
                var option = this._option(name);
                if (option)
                    this._createAction(option)(actionArguments)
            },
            _fireClickAction: function(actionArguments) {
                this._fireAction("clickAction", actionArguments)
            },
            _fireMarkerAddedAction: function(actionArguments) {
                this._fireAction("markerAddedAction", actionArguments)
            },
            _fireMarkerRemovedAction: function(actionArguments) {
                this._fireAction("markerRemovedAction", actionArguments)
            },
            _fireRouteAddedAction: function(actionArguments) {
                this._fireAction("routeAddedAction", actionArguments)
            },
            _fireRouteRemovedAction: function(actionArguments) {
                this._fireAction("routeRemovedAction", actionArguments)
            }
        });
        var providers = {};
        ui.registerMapProvider = function(name, provider) {
            providers[name] = provider
        };
        var MAP_CLASS = "dx-map",
            MAP_CONTAINER_CLASS = "dx-map-container",
            MAP_SHIELD_CLASS = "dx-map-shield";
        DX.registerComponent("dxMap", ui.Widget.inherit({
            ctor: function() {
                this.callBase.apply(this, arguments);
                this.addMarker = $.proxy(this._addFunction, this, "markers");
                this.removeMarker = $.proxy(this._removeFunction, this, "markers");
                this.addRoute = $.proxy(this._addFunction, this, "routes");
                this.removeRoute = $.proxy(this._removeFunction, this, "routes")
            },
            _addFunction: function(optionName, addingValue) {
                var deferred = $.Deferred(),
                    that = this,
                    providerDeffered = $.Deferred(),
                    optionValue = this.option(optionName),
                    addingValues = wrapToArray(addingValue);
                optionValue.push.apply(optionValue, addingValues);
                this._notificationDeffered = providerDeffered;
                this.option(optionName, optionValue);
                providerDeffered.done(function(instance) {
                    deferred.resolveWith(that, instance && instance.length > 1 ? [instance] : instance)
                });
                return deferred.promise()
            },
            _removeFunction: function(optionName, removingValue) {
                var deferred = $.Deferred(),
                    that = this,
                    providerDeffered = $.Deferred(),
                    optionValue = this.option(optionName),
                    removingValues = wrapToArray(removingValue);
                $.each(removingValues, function(_, removingValue) {
                    var index = $.isNumeric(removingValue) ? removingValue : $.inArray(removingValue, optionValue);
                    if (index !== -1)
                        optionValue.splice(index, 1);
                    else
                        throw new Error(titleize(optionName.substring(0, optionName.length - 1)) + " '" + removingValue + "' you are trying to remove does not exist");
                });
                this._notificationDeffered = providerDeffered;
                this.option(optionName, optionValue);
                providerDeffered.done(function() {
                    deferred.resolveWith(that)
                });
                return deferred.promise()
            },
            _deprecatedOptions: {location: {
                    since: "14.1",
                    message: "Use the 'center' option instead."
                }},
            _optionAliases: {center: "location"},
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    center: {
                        lat: 0,
                        lng: 0
                    },
                    location: {
                        lat: 0,
                        lng: 0
                    },
                    width: 300,
                    height: 300,
                    zoom: 1,
                    type: "roadmap",
                    provider: "google",
                    autoAdjust: true,
                    markers: [],
                    markerIconSrc: null,
                    markerAddedAction: null,
                    markerRemovedAction: null,
                    routes: [],
                    routeAddedAction: null,
                    routeRemovedAction: null,
                    key: {
                        bing: "",
                        google: "",
                        googleStatic: ""
                    },
                    controls: false,
                    readyAction: null,
                    updateAction: null,
                    clickAction: null
                })
            },
            _init: function() {
                this._checkMarkersOption(this.option("markers"));
                this._checkRoutesOption(this.option("routes"));
                this.callBase();
                this._initContainer();
                this._grabEvents();
                this._initProvider();
                this._cleanRenderedMarkers();
                this._cleanRenderedRoutes()
            },
            _cleanRenderedMarkers: function() {
                this._renderedMarkers = []
            },
            _cleanRenderedRoutes: function(routes) {
                this._renderedRoutes = []
            },
            _checkMarkersOption: function(markers) {
                if (!$.isArray(markers))
                    throw new Error("Markers option should be an array");
            },
            _checkRoutesOption: function(routes) {
                if (!$.isArray(routes))
                    throw new Error("Routes option should be an array");
            },
            _visibilityChanged: function(visible) {
                if (visible)
                    this._dimensionChanged()
            },
            _dimensionChanged: function() {
                this._execAsyncProviderAction("updateDimensions")
            },
            _initContainer: function() {
                this._$container = $("<div />").addClass(MAP_CONTAINER_CLASS);
                this._element().append(this._$container)
            },
            _grabEvents: function() {
                var eventName = events.addNamespace("dxpointerdown", this.NAME);
                this._element().on(eventName, $.proxy(this._cancelEvent, this))
            },
            _cancelEvent: function(e) {
                var cancelByProvider = this._provider.cancelEvents && !this.option("disabled");
                if (!DX.designMode && cancelByProvider)
                    e.stopPropagation()
            },
            _initProvider: function() {
                var provider = this.option("provider");
                if (winJS && this.option("provider") === "google")
                    throw new Error("Google provider cannot be used in winJS application");
                this._cleanProvider();
                this._provider = new providers[provider](this, this._$container);
                this._mapLoader = this._provider.load()
            },
            _render: function() {
                this.callBase();
                this._element().addClass(MAP_CLASS);
                this._renderShield();
                this._execAsyncProviderAction("render").done($.proxy(function() {
                    this._saveRenderedMarkers();
                    this._saveRenderedRoutes()
                }, this))
            },
            _saveRenderedMarkers: function(markers) {
                markers = markers || this.option("markers");
                this._renderedMarkers = markers.slice()
            },
            _saveRenderedRoutes: function(routes) {
                routes = routes || this.option("routes");
                this._renderedRoutes = routes.slice()
            },
            _renderShield: function() {
                if (DX.designMode || this.option("disabled")) {
                    var $shield = $("<div/>").addClass(MAP_SHIELD_CLASS);
                    this._element().append($shield)
                }
                else {
                    var $shield = this._element().find("." + MAP_SHIELD_CLASS);
                    $shield.remove()
                }
            },
            _clean: function() {
                this._cleanProvider();
                this._cleanRenderedMarkers();
                this._cleanRenderedRoutes()
            },
            _cleanProvider: function() {
                if (this._provider)
                    this._provider.clean()
            },
            _optionChanged: function(name, value, prevValue) {
                if (this._cancelOptionChange)
                    return;
                var notificationDeffered = this._notificationDeffered;
                delete this._notificationDeffered;
                switch (name) {
                    case"disabled":
                        this._renderShield();
                        this.callBase.apply(this, arguments);
                        break;
                    case"width":
                    case"height":
                        this.callBase.apply(this, arguments);
                        this._dimensionChanged();
                        break;
                    case"type":
                        this._execAsyncProviderAction("updateMapType");
                        break;
                    case"center":
                        this._execAsyncProviderAction("updateCenter");
                        break;
                    case"zoom":
                        this._execAsyncProviderAction("updateZoom");
                        break;
                    case"controls":
                        this._execAsyncProviderAction("updateControls");
                        break;
                    case"markers":
                        this._checkMarkersOption(value);
                        this._execAsyncProviderAction("updateMarkers", $.proxy(function() {
                            return notificationDeffered ? removeDublicates(this._renderedMarkers, value) : this._renderedMarkers
                        }, this), $.proxy(function() {
                            return notificationDeffered ? removeDublicates(value, this._renderedMarkers) : value
                        }, this)).done($.proxy(function() {
                            this._saveRenderedMarkers(value);
                            if (notificationDeffered)
                                notificationDeffered.resolve.apply(notificationDeffered, arguments)
                        }, this));
                        break;
                    case"markerIconSrc":
                        this._execAsyncProviderAction("updateMarkers", prevValue, value);
                        break;
                    case"autoAdjust":
                        this._execAsyncProviderAction("adjustViewport");
                        break;
                    case"routes":
                        this._checkRoutesOption(value);
                        this._execAsyncProviderAction("updateRoutes", $.proxy(function() {
                            return notificationDeffered ? removeDublicates(this._renderedRoutes, value) : this._renderedRoutes
                        }, this), $.proxy(function() {
                            return notificationDeffered ? removeDublicates(value, this._renderedRoutes) : value
                        }, this)).done($.proxy(function() {
                            this._saveRenderedRoutes(value);
                            if (notificationDeffered)
                                notificationDeffered.resolve.apply(notificationDeffered, arguments)
                        }, this));
                        break;
                    case"key":
                        utils.logger.warn("Key option can not be modified after initialization");
                    case"provider":
                        this._initProvider();
                        this._invalidate();
                        break;
                    case"readyAction":
                    case"updateAction":
                    case"markerAddedAction":
                    case"markerRemovedAction":
                    case"routeAddedAction":
                    case"routeRemovedAction":
                    case"clickAction":
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _execAsyncProviderAction: function(name) {
                if (!this._provider.mapRendered() && !(name === "render"))
                    return $.when(undefined).promise();
                var deferred = $.Deferred(),
                    that = this,
                    options = $.makeArray(arguments).slice(1);
                $.when(this._mapLoader).done(function() {
                    var provider = that._provider;
                    $.each(options, function(index, option) {
                        if ($.isFunction(option))
                            options[index] = option()
                    });
                    provider[name].apply(provider, options).done(function(mapRefreshed) {
                        deferred.resolve.apply(deferred, $.makeArray(arguments).slice(1));
                        if (mapRefreshed)
                            that._triggerReadyAction();
                        else
                            that._triggerUpdateAction()
                    })
                });
                return deferred.promise()
            },
            _triggerReadyAction: function() {
                this._createActionByOption("readyAction")({originalMap: this._provider.map()})
            },
            _triggerUpdateAction: function() {
                this._createActionByOption("updateAction")()
            },
            setOptionSilent: function(name, value) {
                this._cancelOptionChange = true;
                this.option(name, value);
                this._cancelOptionChange = false
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.map.bing.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            winJS = DX.support.winJS;
        var BING_MAP_READY = "_bingScriptReady",
            BING_URL = "https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&s=1&onScriptLoad=" + BING_MAP_READY,
            BING_LOCAL_FILES1 = "ms-appx:///Bing.Maps.JavaScript/js/veapicore.js",
            BING_LOCAL_FILES2 = "ms-appx:///Bing.Maps.JavaScript/js/veapiModules.js",
            BING_CREDENTIALS = "AhuxC0dQ1DBTNo8L-H9ToVMQStmizZzBJdraTSgCzDSWPsA1Qd8uIvFSflzxdaLH",
            MIN_LOCATION_RECT_LENGTH = 0.0000000000000001;
        var msMapsLoader;
        ui.registerMapProvider("bing", ui.MapProvider.inherit({
            _mapType: function(type) {
                var mapTypes = {
                        roadmap: Microsoft.Maps.MapTypeId.road,
                        hybrid: Microsoft.Maps.MapTypeId.aerial
                    };
                return mapTypes[type] || mapTypes.roadmap
            },
            _movementMode: function(type) {
                var movementTypes = {
                        driving: Microsoft.Maps.Directions.RouteMode.driving,
                        walking: Microsoft.Maps.Directions.RouteMode.walking
                    };
                return movementTypes[type] || movementTypes.driving
            },
            _resolveLocation: function(location) {
                var d = $.Deferred();
                if (typeof location === "string") {
                    var searchManager = new Microsoft.Maps.Search.SearchManager(this._map);
                    var searchRequest = {
                            where: location,
                            count: 1,
                            callback: function(searchResponse) {
                                var boundsBox = searchResponse.results[0].location;
                                d.resolve(new Microsoft.Maps.Location(boundsBox.latitude, boundsBox.longitude))
                            }
                        };
                    searchManager.geocode(searchRequest)
                }
                else if ($.isPlainObject(location) && $.isNumeric(location.lat) && $.isNumeric(location.lng))
                    d.resolve(new Microsoft.Maps.Location(location.lat, location.lng));
                else if ($.isArray(location))
                    d.resolve(new Microsoft.Maps.Location(location[0], location[1]));
                return d.promise()
            },
            _normalizeLocation: function(location) {
                return {
                        lat: location.latitude,
                        lng: location.longitude
                    }
            },
            load: function() {
                if (!msMapsLoader) {
                    msMapsLoader = $.Deferred();
                    window[BING_MAP_READY] = $.proxy(this._mapReady, this);
                    if (winJS)
                        $.when($.getScript(BING_LOCAL_FILES1), $.getScript(BING_LOCAL_FILES2)).done(function() {
                            Microsoft.Maps.loadModule("Microsoft.Maps.Map", {callback: window[BING_MAP_READY]})
                        });
                    else
                        $.getScript(BING_URL)
                }
                this._markers = [];
                this._routes = [];
                return msMapsLoader
            },
            _mapReady: function() {
                try {
                    delete window[BING_MAP_READY]
                }
                catch(e) {
                    window[BING_MAP_READY] = undefined
                }
                var searchModulePromise = $.Deferred();
                var directionsModulePromise = $.Deferred();
                Microsoft.Maps.loadModule('Microsoft.Maps.Search', {callback: $.proxy(searchModulePromise.resolve, searchModulePromise)});
                Microsoft.Maps.loadModule('Microsoft.Maps.Directions', {callback: $.proxy(directionsModulePromise.resolve, directionsModulePromise)});
                $.when(searchModulePromise, directionsModulePromise).done(function() {
                    msMapsLoader.resolve()
                })
            },
            _renderImpl: function() {
                var deferred = $.Deferred(),
                    initPromise = $.Deferred(),
                    controls = this._option("controls");
                var options = {
                        credentials: this._keyOption("bing") || BING_CREDENTIALS,
                        mapTypeId: this._mapType(this._option("type")),
                        zoom: this._option("zoom"),
                        showDashboard: controls,
                        showMapTypeSelector: controls,
                        showScalebar: controls
                    };
                this._map = new Microsoft.Maps.Map(this._$container[0], options);
                var handler = Microsoft.Maps.Events.addHandler(this._map, 'tiledownloadcomplete', $.proxy(initPromise.resolve, initPromise));
                this._viewChangeHandler = Microsoft.Maps.Events.addHandler(this._map, 'viewchange', $.proxy(this._handleViewChange, this));
                this._clickHandler = Microsoft.Maps.Events.addHandler(this._map, 'click', $.proxy(this._handleClickAction, this));
                var locationPromise = this._renderCenter();
                $.when(initPromise, locationPromise).done(function() {
                    Microsoft.Maps.Events.removeHandler(handler);
                    deferred.resolve()
                });
                return deferred.promise()
            },
            _handleViewChange: function() {
                var center = this._map.getCenter();
                this._option("center", this._normalizeLocation(center));
                if (!this._preventZoomChangeEvent)
                    this._option("zoom", this._map.getZoom())
            },
            updateDimensions: function() {
                this._map.setOptions({
                    width: this._$container.width(),
                    height: this._$container.height()
                });
                return $.Deferred().resolve().promise()
            },
            updateMapType: function() {
                this._map.setView({mapTypeId: this._mapType(this._option("type"))});
                return $.Deferred().resolve().promise()
            },
            updateCenter: function() {
                return this._renderCenter()
            },
            _renderCenter: function() {
                var deferred = $.Deferred(),
                    that = this;
                this._resolveLocation(this._option("center")).done(function(location) {
                    that._map.setView({
                        animate: false,
                        center: location
                    });
                    deferred.resolve()
                });
                return deferred.promise()
            },
            updateZoom: function() {
                this._map.setView({
                    animate: false,
                    zoom: this._option("zoom")
                });
                return $.Deferred().resolve().promise()
            },
            updateControls: function() {
                this.clean();
                return this.render()
            },
            addMarkers: function(options) {
                var deferred = $.Deferred(),
                    that = this;
                var markerPromises = $.map(options, function(options) {
                        return that._addMarker(options)
                    });
                $.when.apply($, markerPromises).done(function() {
                    var instances = $.map($.makeArray(arguments), function(markerObject) {
                            return markerObject.pushpin
                        });
                    deferred.resolve(false, instances)
                });
                return deferred.promise()
            },
            _addMarker: function(options) {
                var that = this;
                return this._renderMarker(options).done(function(markerObject) {
                        that._markers.push($.extend({options: options}, markerObject));
                        that._updateMarkersBounds();
                        that._fitBounds();
                        that._fireMarkerAddedAction({
                            options: options,
                            originalMarker: markerObject.pushpin
                        })
                    })
            },
            _renderMarker: function(options) {
                var d = $.Deferred(),
                    that = this;
                this._resolveLocation(options.location).done(function(location) {
                    var pushpin = new Microsoft.Maps.Pushpin(location, {icon: options.iconSrc || that._option("markerIconSrc")});
                    that._map.entities.push(pushpin);
                    var infobox = that._renderTooltip(location, options.tooltip);
                    var handler;
                    if (options.clickAction || options.tooltip) {
                        var markerClickAction = that._createAction(options.clickAction || $.noop),
                            markerNormalizedLocation = that._normalizeLocation(location);
                        handler = Microsoft.Maps.Events.addHandler(pushpin, "click", function() {
                            markerClickAction({location: markerNormalizedLocation});
                            if (infobox)
                                infobox.setOptions({visible: true})
                        })
                    }
                    d.resolve({
                        location: location,
                        pushpin: pushpin,
                        infobox: infobox,
                        handler: handler
                    })
                });
                return d.promise()
            },
            _renderTooltip: function(location, options) {
                if (!options)
                    return;
                options = this._parseTooltipOptions(options);
                var infobox = new Microsoft.Maps.Infobox(location, {
                        description: options.text,
                        offset: new Microsoft.Maps.Point(0, 33),
                        visible: options.visible
                    });
                this._map.entities.push(infobox, null);
                return infobox
            },
            removeMarkers: function(options) {
                var that = this;
                $.each(options, function(_, options) {
                    that._removeMarker(options)
                });
                return $.Deferred().resolve().promise()
            },
            _removeMarker: function(options) {
                var that = this;
                $.each(this._markers, function(markerIndex, markerObject) {
                    if (markerObject.options !== options)
                        return true;
                    var marker = that._markers[markerIndex];
                    that._map.entities.remove(marker.pushpin);
                    if (marker.infobox)
                        that._map.entities.remove(marker.infobox);
                    if (marker.handler)
                        Microsoft.Maps.Events.removeHandler(marker.handler);
                    that._markers.splice(markerIndex, 1);
                    that._updateMarkersBounds();
                    that._fitBounds();
                    that._fireMarkerRemovedAction({options: options});
                    return false
                })
            },
            _updateMarkersBounds: function() {
                var that = this;
                this._clearBounds();
                $.each(this._markers, function(_, markerObject) {
                    that._extendBounds(markerObject.location)
                })
            },
            _clearMarkers: function() {
                for (var i = 0; this._markers.length > 0; )
                    this._removeMarker(this._markers[0].options)
            },
            adjustViewport: function() {
                return this._fitBounds()
            },
            _clearBounds: function() {
                this._bounds = null
            },
            _extendBounds: function(location) {
                if (this._bounds)
                    this._bounds = new Microsoft.Maps.LocationRect.fromLocations(this._bounds.getNorthwest(), this._bounds.getSoutheast(), location);
                else
                    this._bounds = new Microsoft.Maps.LocationRect(location, MIN_LOCATION_RECT_LENGTH, MIN_LOCATION_RECT_LENGTH)
            },
            _fitBounds: function() {
                var autoAdjust = this._option("autoAdjust");
                if (this._bounds && autoAdjust) {
                    var zoomBeforeFitting = this._map.getZoom();
                    this._preventZoomChangeEvent = true;
                    var bounds = this._bounds.clone();
                    bounds.height = bounds.height * 1.1;
                    bounds.width = bounds.width * 1.1;
                    this._map.setView({
                        animate: false,
                        bounds: bounds
                    });
                    var zoomAfterFitting = this._map.getZoom();
                    if (zoomBeforeFitting < zoomAfterFitting)
                        this._map.setView({
                            animate: false,
                            zoom: zoomBeforeFitting
                        });
                    else
                        this._option("zoom", zoomAfterFitting);
                    delete this._preventZoomChangeEvent
                }
                return $.Deferred().resolve().promise()
            },
            addRoutes: function(options) {
                var deferred = $.Deferred(),
                    that = this;
                var routePromises = $.map(options, function(options) {
                        return that._addRoute(options)
                    });
                $.when.apply($, routePromises).done(function() {
                    deferred.resolve(false, $.makeArray(arguments))
                });
                return deferred.promise()
            },
            _addRoute: function(options) {
                var that = this;
                return this._renderRoute(options).done(function(instance) {
                        that._routes.push({
                            options: options,
                            instance: instance
                        });
                        that._fireRouteAddedAction({
                            options: options,
                            originalRoute: instance
                        })
                    })
            },
            _renderRoute: function(options) {
                var d = $.Deferred(),
                    that = this;
                var points = $.map(options.locations, function(point) {
                        return that._resolveLocation(point)
                    });
                $.when.apply($, points).done(function() {
                    var locations = $.makeArray(arguments),
                        direction = new Microsoft.Maps.Directions.DirectionsManager(that._map),
                        color = new DX.Color(options.color || that._defaultRouteColor()).toHex(),
                        routeColor = new Microsoft.Maps.Color.fromHex(color);
                    routeColor.a = (options.opacity || that._defaultRouteOpacity()) * 255;
                    direction.setRenderOptions({
                        autoUpdateMapView: false,
                        displayRouteSelector: false,
                        waypointPushpinOptions: {visible: false},
                        drivingPolylineOptions: {
                            strokeColor: routeColor,
                            strokeThickness: options.weight || that._defaultRouteWeight()
                        },
                        walkingPolylineOptions: {
                            strokeColor: routeColor,
                            strokeThickness: options.weight || that._defaultRouteWeight()
                        }
                    });
                    direction.setRequestOptions({
                        routeMode: that._movementMode(options.mode),
                        routeDraggable: false
                    });
                    $.each(locations, function(_, location) {
                        var waypoint = new Microsoft.Maps.Directions.Waypoint({location: location});
                        direction.addWaypoint(waypoint)
                    });
                    var handler = Microsoft.Maps.Events.addHandler(direction, 'directionsUpdated', function() {
                            Microsoft.Maps.Events.removeHandler(handler);
                            d.resolve(direction)
                        });
                    direction.calculateDirections()
                });
                return d.promise()
            },
            removeRoutes: function(options) {
                var that = this;
                $.each(options, function(routeIndex, options) {
                    that._removeRoute(options)
                });
                return $.Deferred().resolve().promise()
            },
            _removeRoute: function(options) {
                var that = this;
                $.each(this._routes, function(routeIndex, routeObject) {
                    if (routeObject.options !== options)
                        return true;
                    that._routes[routeIndex].instance.dispose();
                    that._routes.splice(routeIndex, 1);
                    that._fireRouteRemovedAction({options: options});
                    return false
                })
            },
            _clearRoutes: function() {
                for (var i = 0; this._routes.length > 0; )
                    this._removeRoute(this._routes[0].options)
            },
            _handleClickAction: function(e) {
                if (e.targetType == "map") {
                    var point = new Microsoft.Maps.Point(e.getX(), e.getY()),
                        location = e.target.tryPixelToLocation(point);
                    this._fireClickAction({location: this._normalizeLocation(location)})
                }
            },
            clean: function() {
                if (this._map) {
                    Microsoft.Maps.Events.removeHandler(this._viewChangeHandler);
                    Microsoft.Maps.Events.removeHandler(this._clickHandler);
                    this._clearMarkers();
                    this._clearRoutes();
                    this._map.dispose()
                }
            },
            cancelEvents: true
        }));
        if (!ui.dxMap.__internals)
            ui.dxMap.__internals = {};
        $.extend(ui.dxMap.__internals, {remapBingConstant: function(newValue) {
                BING_URL = newValue
            }})
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.map.google.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var GOOGLE_MAP_READY = "_googleScriptReady",
            GOOGLE_URL = "https://maps.google.com/maps/api/js?v=3.9&sensor=false&callback=" + GOOGLE_MAP_READY;
        var googleMapsLoader;
        ui.registerMapProvider("google", ui.MapProvider.inherit({
            _mapType: function(type) {
                var mapTypes = {
                        hybrid: google.maps.MapTypeId.HYBRID,
                        roadmap: google.maps.MapTypeId.ROADMAP
                    };
                return mapTypes[type] || mapTypes.hybrid
            },
            _movementMode: function(type) {
                var movementTypes = {
                        driving: google.maps.TravelMode.DRIVING,
                        walking: google.maps.TravelMode.WALKING
                    };
                return movementTypes[type] || movementTypes.driving
            },
            _resolveLocation: function(location) {
                var d = $.Deferred();
                if (typeof location === "string") {
                    var geocoder = new google.maps.Geocoder;
                    geocoder.geocode({address: location}, function(results, status) {
                        if (status === google.maps.GeocoderStatus.OK)
                            d.resolve(results[0].geometry.location)
                    })
                }
                else if ($.isArray(location))
                    d.resolve(new google.maps.LatLng(location[0], location[1]));
                else if ($.isPlainObject(location) && $.isNumeric(location.lat) && $.isNumeric(location.lng))
                    d.resolve(new google.maps.LatLng(location.lat, location.lng));
                return d.promise()
            },
            _normalizeLocation: function(location) {
                return {
                        lat: location.lat(),
                        lng: location.lng()
                    }
            },
            load: function() {
                if (!googleMapsLoader) {
                    googleMapsLoader = $.Deferred();
                    var key = this._keyOption("google");
                    window[GOOGLE_MAP_READY] = $.proxy(this._mapReady, this);
                    $.getScript(GOOGLE_URL + (key ? "&key=" + key : ""))
                }
                this._markers = [];
                this._routes = [];
                return googleMapsLoader.promise()
            },
            _mapReady: function() {
                try {
                    delete window[GOOGLE_MAP_READY]
                }
                catch(e) {
                    window[GOOGLE_MAP_READY] = undefined
                }
                googleMapsLoader.resolve()
            },
            _renderImpl: function() {
                var deferred = $.Deferred(),
                    initPromise = $.Deferred(),
                    controls = this._option("controls");
                var options = {
                        zoom: this._option("zoom"),
                        center: new google.maps.LatLng(0, 0),
                        mapTypeId: this._mapType(this._option("type")),
                        panControl: controls,
                        zoomControl: controls,
                        mapTypeControl: controls,
                        streetViewControl: controls
                    };
                this._map = new google.maps.Map(this._$container[0], options);
                var listner = google.maps.event.addListener(this._map, 'idle', $.proxy(initPromise.resolve, initPromise));
                this._zoomChangeListener = google.maps.event.addListener(this._map, 'zoom_changed', $.proxy(this._handleZoomChange, this));
                this._centerChangeListener = google.maps.event.addListener(this._map, 'center_changed', $.proxy(this._handleCenterChange, this));
                this._clickListener = google.maps.event.addListener(this._map, 'click', $.proxy(this._handleClickAction, this));
                var locationPromise = this._renderCenter();
                $.when(initPromise, locationPromise).done(function() {
                    google.maps.event.removeListener(listner);
                    deferred.resolve()
                });
                return deferred.promise()
            },
            updateDimensions: function() {
                google.maps.event.trigger(this._map, 'resize');
                return $.Deferred().resolve().promise()
            },
            updateMapType: function() {
                this._map.setMapTypeId(this._mapType(this._option("type")));
                return $.Deferred().resolve().promise()
            },
            updateCenter: function() {
                return this._renderCenter()
            },
            _handleCenterChange: function() {
                var center = this._map.getCenter();
                this._option("center", this._normalizeLocation(center))
            },
            _renderCenter: function() {
                var deferred = $.Deferred(),
                    that = this;
                this._resolveLocation(this._option("center")).done(function(location) {
                    that._map.setCenter(location);
                    deferred.resolve()
                });
                return deferred.promise()
            },
            _handleZoomChange: function() {
                if (!this._preventZoomChangeEvent)
                    this._option("zoom", this._map.getZoom())
            },
            updateZoom: function() {
                this._map.setZoom(this._option("zoom"));
                return $.Deferred().resolve().promise()
            },
            updateControls: function() {
                var controls = this._option("controls");
                this._map.setOptions({
                    panControl: controls,
                    zoomControl: controls,
                    mapTypeControl: controls,
                    streetViewControl: controls
                });
                return $.Deferred().resolve().promise()
            },
            addMarkers: function(options) {
                var deferred = $.Deferred(),
                    that = this;
                var markerPromises = $.map(options, function(options) {
                        return that._addMarker(options)
                    });
                $.when.apply($, markerPromises).done(function() {
                    var instances = $.map($.makeArray(arguments), function(markerObject) {
                            return markerObject.marker
                        });
                    deferred.resolve(false, instances)
                });
                return deferred.promise()
            },
            _addMarker: function(options) {
                var that = this;
                return this._renderMarker(options).done(function(markerObject) {
                        that._markers.push($.extend({options: options}, markerObject));
                        that._updateMarkersBounds();
                        that._fitBounds();
                        that._fireMarkerAddedAction({
                            options: options,
                            originalMarker: markerObject.marker
                        })
                    })
            },
            _renderMarker: function(options) {
                var d = $.Deferred(),
                    that = this;
                this._resolveLocation(options.location).done(function(location) {
                    var marker = new google.maps.Marker({
                            position: location,
                            map: that._map,
                            icon: options.iconSrc || that._option("markerIconSrc")
                        }),
                        listner;
                    var infoWindow = that._renderTooltip(marker, options.tooltip);
                    if (options.clickAction || options.tooltip) {
                        var markerClickAction = that._createAction(options.clickAction || $.noop),
                            markerNormalizedLocation = that._normalizeLocation(location);
                        listner = google.maps.event.addListener(marker, "click", function() {
                            markerClickAction({location: markerNormalizedLocation});
                            if (infoWindow)
                                infoWindow.open(that._map, marker)
                        })
                    }
                    d.resolve({
                        location: location,
                        marker: marker,
                        listner: listner
                    })
                });
                return d.promise()
            },
            _renderTooltip: function(marker, options) {
                if (!options)
                    return;
                options = this._parseTooltipOptions(options);
                var infoWindow = new google.maps.InfoWindow({content: options.text});
                if (options.visible)
                    infoWindow.open(this._map, marker);
                return infoWindow
            },
            removeMarkers: function(markersOptionsToRemove) {
                var that = this;
                $.each(markersOptionsToRemove, function(_, markerOptionToRemove) {
                    that._removeMarker(markerOptionToRemove)
                });
                return $.Deferred().resolve().promise()
            },
            _removeMarker: function(markersOptionToRemove) {
                var that = this;
                $.each(this._markers, function(markerIndex, markerObject) {
                    if (markerObject.options !== markersOptionToRemove)
                        return true;
                    var marker = that._markers[markerIndex];
                    marker.marker.setMap(null);
                    if (marker.listner)
                        google.maps.event.removeListener(marker.listner);
                    that._markers.splice(markerIndex, 1);
                    that._updateMarkersBounds();
                    that._fitBounds();
                    that._fireMarkerRemovedAction({options: markerObject.options});
                    return false
                })
            },
            _updateMarkersBounds: function() {
                var that = this;
                this._clearBounds();
                $.each(this._markers, function(_, markerObject) {
                    that._extendBounds(markerObject.location)
                })
            },
            _clearMarkers: function() {
                for (var i = 0; this._markers.length > 0; )
                    this._removeMarker(this._markers[0].options)
            },
            adjustViewport: function() {
                return this._fitBounds()
            },
            _extendBounds: function(location) {
                if (this._bounds)
                    this._bounds.extend(location);
                else {
                    this._bounds = new google.maps.LatLngBounds;
                    this._bounds.extend(location)
                }
            },
            _fitBounds: function() {
                var autoAdjust = this._option("autoAdjust");
                if (this._bounds && autoAdjust) {
                    var zoomBeforeFitting = this._map.getZoom();
                    this._preventZoomChangeEvent = true;
                    this._map.fitBounds(this._bounds);
                    var zoomAfterFitting = this._map.getZoom();
                    if (zoomBeforeFitting < zoomAfterFitting)
                        this._map.setZoom(zoomBeforeFitting);
                    else
                        this._option("zoom", zoomAfterFitting);
                    delete this._preventZoomChangeEvent
                }
                return $.Deferred().resolve().promise()
            },
            _clearBounds: function() {
                this._bounds = null
            },
            addRoutes: function(options) {
                var deferred = $.Deferred(),
                    that = this;
                var routePromises = $.map(options, function(options) {
                        return that._addRoute(options)
                    });
                $.when.apply($, routePromises).done(function() {
                    deferred.resolve(false, $.makeArray(arguments))
                });
                return deferred.promise()
            },
            _addRoute: function(options) {
                var that = this;
                return this._renderRoute(options).done(function(instance) {
                        that._routes.push({
                            options: options,
                            instance: instance
                        });
                        that._fireRouteAddedAction({
                            options: options,
                            originalRoute: instance
                        })
                    })
            },
            _renderRoute: function(options) {
                var d = $.Deferred(),
                    that = this,
                    directionsService = new google.maps.DirectionsService;
                var points = $.map(options.locations, function(point) {
                        return that._resolveLocation(point)
                    });
                $.when.apply($, points).done(function() {
                    var locations = $.makeArray(arguments),
                        origin = locations.shift(),
                        destination = locations.pop(),
                        waypoints = $.map(locations, function(location) {
                            return {
                                    location: location,
                                    stopover: true
                                }
                        });
                    var request = {
                            origin: origin,
                            destination: destination,
                            waypoints: waypoints,
                            optimizeWaypoints: true,
                            travelMode: that._movementMode(options.mode)
                        };
                    directionsService.route(request, function(response, status) {
                        if (status === google.maps.DirectionsStatus.OK) {
                            var color = new DX.Color(options.color || that._defaultRouteColor()).toHex(),
                                directionOptions = {
                                    directions: response,
                                    map: that._map,
                                    suppressMarkers: true,
                                    preserveViewport: true,
                                    polylineOptions: {
                                        strokeWeight: options.weight || that._defaultRouteWeight(),
                                        strokeOpacity: options.opacity || that._defaultRouteOpacity(),
                                        strokeColor: color
                                    }
                                };
                            var route = new google.maps.DirectionsRenderer(directionOptions);
                            d.resolve(route)
                        }
                    })
                });
                return d.promise()
            },
            removeRoutes: function(options) {
                var that = this;
                $.each(options, function(routeIndex, options) {
                    that._removeRoute(options)
                });
                return $.Deferred().resolve().promise()
            },
            _removeRoute: function(options) {
                var that = this;
                $.each(this._routes, function(routeIndex, routeObject) {
                    if (routeObject.options !== options)
                        return true;
                    that._routes[routeIndex].instance.setMap(null);
                    that._routes.splice(routeIndex, 1);
                    that._fireRouteRemovedAction({options: options});
                    return false
                })
            },
            _clearRoutes: function() {
                for (var i = 0; this._routes.length > 0; )
                    this._removeRoute(this._routes[0].options)
            },
            _handleClickAction: function(e) {
                this._fireClickAction({location: this._normalizeLocation(e.latLng)})
            },
            clean: function() {
                if (this._map) {
                    google.maps.event.removeListener(this._zoomChangeListener);
                    google.maps.event.removeListener(this._centerChangeListener);
                    google.maps.event.removeListener(this._clickListener);
                    this._clearMarkers();
                    this._clearRoutes();
                    delete this._map;
                    this._$container.empty()
                }
            },
            cancelEvents: true
        }));
        if (!ui.dxMap.__internals)
            ui.dxMap.__internals = {};
        $.extend(ui.dxMap.__internals, {remapGoogleConstant: function(newValue) {
                GOOGLE_URL = newValue
            }})
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.map.googleStatic.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var GOOGLE_STATIC_URL = "https://maps.google.com/maps/api/staticmap?";
        ui.registerMapProvider("googleStatic", ui.MapProvider.inherit({
            _locationToString: function(location) {
                return !$.isPlainObject(location) ? location.toString().replace(/ /g, "+") : location.lat + "," + location.lng
            },
            _renderImpl: function() {
                return this._updateMap()
            },
            updateDimensions: function() {
                return this._updateMap()
            },
            updateMapType: function() {
                return this._updateMap()
            },
            updateCenter: function() {
                return this._updateMap()
            },
            updateZoom: function() {
                return this._updateMap()
            },
            updateControls: function() {
                return $.Deferred().resolve().promise()
            },
            addMarkers: function(options) {
                var that = this;
                return this._updateMap().done(function() {
                        $.each(options, function(_, options) {
                            that._fireMarkerAddedAction({options: options})
                        })
                    })
            },
            removeMarkers: function(options) {
                var that = this;
                return this._updateMap().done(function() {
                        $.each(options, function(_, options) {
                            that._fireMarkerRemovedAction({options: options})
                        })
                    })
            },
            adjustViewport: function() {
                return $.Deferred().resolve().promise()
            },
            addRoutes: function(options) {
                var that = this;
                return this._updateMap().done(function() {
                        $.each(options, function(_, options) {
                            that._fireRouteAddedAction({options: options})
                        })
                    })
            },
            removeRoutes: function(options) {
                var that = this;
                return this._updateMap().done(function() {
                        $.each(options, function(_, options) {
                            that._fireRouteRemovedAction({options: options})
                        })
                    })
            },
            clean: function() {
                this._$container.css("background-image", "none");
                this._$container.off(this._addEventNamespace("dxclick"))
            },
            mapRendered: function() {
                return true
            },
            _updateMap: function() {
                var key = this._keyOption("googleStatic");
                var requestOptions = ["sensor=false", "size=" + this._option("width") + "x" + this._option("height"), "maptype=" + this._option("type"), "center=" + this._locationToString(this._option("center")), "zoom=" + this._option("zoom"), this._markersSubstring()];
                requestOptions.push.apply(requestOptions, this._routeSubstrings());
                if (key)
                    requestOptions.push("key=" + key);
                var request = GOOGLE_STATIC_URL + requestOptions.join("&");
                this._$container.css("background", "url(\"" + request + "\") no-repeat 0 0");
                this._attachClickEvent();
                return $.Deferred().resolve(true).promise()
            },
            _markersSubstring: function() {
                var that = this,
                    markers = [],
                    markerIcon = this._option("markerIconSrc");
                if (markerIcon)
                    markers.push("icon:" + markerIcon);
                $.each(this._option("markers"), function(_, marker) {
                    markers.push(that._locationToString(marker.location))
                });
                return "markers=" + markers.join("|")
            },
            _routeSubstrings: function() {
                var that = this,
                    routes = [];
                $.each(this._option("routes"), function(_, route) {
                    var color = new DX.Color(route.color || that._defaultRouteColor()).toHex().replace('#', '0x'),
                        opacity = Math.round((route.opacity || that._defaultRouteOpacity()) * 255).toString(16),
                        width = route.weight || that._defaultRouteWeight(),
                        locations = [];
                    $.each(route.locations, function(_, routePoint) {
                        locations.push(that._locationToString(routePoint))
                    });
                    routes.push("path=color:" + color + opacity + "|weight:" + width + "|" + locations.join("|"))
                });
                return routes
            },
            _attachClickEvent: function() {
                var that = this,
                    eventName = this._addEventNamespace("dxclick");
                this._$container.off(eventName).on(eventName, function(e) {
                    that._fireClickAction({jQueryEvent: e})
                })
            }
        }));
        if (!ui.dxMap.__internals)
            ui.dxMap.__internals = {};
        $.extend(ui.dxMap.__internals, {remapGoogleStaticConstant: function(newValue) {
                GOOGLE_STATIC_URL = newValue
            }})
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.swipeable.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            DX_SWIPEABLE = "dxSwipeable",
            SWIPEABLE_CLASS = "dx-swipeable",
            ACTION_TO_EVENT_MAP = {
                startAction: "dxswipestart",
                updateAction: "dxswipe",
                endAction: "dxswipeend",
                cancelAction: "dxswipecancel"
            };
        DX.registerComponent(DX_SWIPEABLE, DX.DOMComponent.inherit({
            NAMESPACE: ui,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    elastic: true,
                    direction: "horizontal",
                    itemSizeFunc: null,
                    startAction: null,
                    updateAction: null,
                    endAction: null,
                    cancelAction: null
                })
            },
            _render: function() {
                this.callBase();
                this._element().addClass(SWIPEABLE_CLASS);
                this._attachEventHandlers()
            },
            _attachEventHandlers: function() {
                if (this.option("disabled"))
                    return;
                var NAME = this.NAME;
                this._createEventData();
                $.each(ACTION_TO_EVENT_MAP, $.proxy(function(actionName, eventName) {
                    var action = this._createActionByOption(actionName, {
                            context: this,
                            excludeValidators: ["gesture"]
                        });
                    eventName = events.addNamespace(eventName, NAME);
                    this._element().off(eventName).on(eventName, this._eventData, function(e) {
                        return action({jQueryEvent: e})
                    })
                }, this))
            },
            _createEventData: function() {
                this._eventData = {
                    elastic: this.option("elastic"),
                    itemSizeFunc: this.option("itemSizeFunc"),
                    direction: this.option("direction")
                }
            },
            _detachEventHanlers: function() {
                this._element().off("." + DX_SWIPEABLE)
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"disabled":
                    case"startAction":
                    case"updateAction":
                    case"endAction":
                    case"cancelAction":
                    case"elastic":
                    case"itemSizeFunc":
                    case"direction":
                        this._detachEventHanlers();
                        this._attachEventHandlers();
                        break;
                    case"rtlEnabled":
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.button.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var BUTTON_CLASS = "dx-button",
            BUTTON_CONTENT_CLASS = "dx-button-content",
            BUTTON_CONTENT_SELECTOR = ".dx-button-content",
            BUTTON_TEXT_CLASS = "dx-button-text",
            BUTTON_HAS_TEXT_CLASS = "dx-button-has-text",
            BUTTON_HAS_ICON_CLASS = "dx-button-has-icon",
            BUTTON_TEXT_SELECTOR = ".dx-button-text",
            BUTTON_BACK_ARROW_CLASS = "dx-button-back-arrow",
            ICON_CLASS = "dx-icon",
            ICON_SELECTOR = ".dx-icon",
            BUTTON_FEEDBACK_HIDE_TIMEOUT = 100;
        DX.registerComponent("dxButton", ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    clickAction: null,
                    type: "normal",
                    text: "",
                    icon: "",
                    iconSrc: ""
                })
            },
            _init: function() {
                this.callBase();
                this._feedbackHideTimeout = BUTTON_FEEDBACK_HIDE_TIMEOUT
            },
            _render: function() {
                this.callBase();
                this._element().addClass(BUTTON_CLASS).append($("<div />").addClass(BUTTON_CONTENT_CLASS));
                this._renderClick();
                this._renderIcon();
                this._renderType();
                this._renderText()
            },
            _renderClick: function() {
                var that = this,
                    eventName = events.addNamespace("dxclick", this.NAME);
                this._clickAction = this._createActionByOption("clickAction");
                this._element().off(eventName).on(eventName, function(e) {
                    that._clickAction({jQueryEvent: e})
                })
            },
            _removeTypesCss: function() {
                var css = this._element().attr("class");
                css = css.replace(/\bdx-button-[-a-z0-9]+\b/gi, "");
                this._element().attr("class", css)
            },
            _renderIcon: function() {
                var contentElement = this._element().find(BUTTON_CONTENT_SELECTOR),
                    iconElement = contentElement.find(ICON_SELECTOR),
                    icon = this.option("icon"),
                    iconSrc = this.option("iconSrc");
                iconElement.remove();
                if (this.option("type") === "back" && !icon)
                    icon = "back";
                if (!icon && !iconSrc)
                    return;
                if (icon)
                    iconElement = $("<span />").addClass("dx-icon-" + icon);
                else if (iconSrc)
                    iconElement = $("<img />").attr("src", iconSrc);
                contentElement.prepend(iconElement.addClass(ICON_CLASS));
                this._element().addClass(BUTTON_HAS_ICON_CLASS)
            },
            _renderType: function() {
                var type = this.option("type");
                if (type)
                    this._element().addClass("dx-button-" + type);
                if (type === "back")
                    this._element().prepend($("<span />").addClass(BUTTON_BACK_ARROW_CLASS))
            },
            _renderText: function() {
                var text = this.option("text"),
                    contentElement = this._element().find(BUTTON_CONTENT_SELECTOR),
                    back = this.option("type") === "back";
                var textElement = contentElement.find(BUTTON_TEXT_SELECTOR);
                if (!text && !back) {
                    textElement.remove();
                    return
                }
                if (!textElement.length)
                    textElement = $('<span />').addClass(BUTTON_TEXT_CLASS).appendTo(contentElement);
                textElement.text(text || DX.localization.localizeString("@Back"));
                this._element().addClass(BUTTON_HAS_TEXT_CLASS)
            },
            _clean: function() {
                this.callBase();
                this._removeTypesCss()
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"clickAction":
                        this._renderClick();
                        break;
                    case"icon":
                    case"iconSrc":
                        this._renderIcon();
                        break;
                    case"text":
                        this._renderText();
                        break;
                    case"type":
                        this._invalidate();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.checkBox.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var CHECKBOX_CLASS = "dx-checkbox",
            CHECKBOX_ICON_CLASS = "dx-checkbox-icon",
            CHECKBOX_CHECKED_CLASS = "dx-checkbox-checked",
            CHECKBOX_INDETERMINATE_CLASS = "dx-checkbox-indeterminate",
            CHECKBOX_FEEDBACK_HIDE_TIMEOUT = 100,
            CHECKBOX_DXCLICK_EVENT_NAME = events.addNamespace("dxclick", "dxCheckBox");
        DX.registerComponent("dxCheckBox", ui.dxEditor.inherit({
            _deprecatedOptions: {checked: {
                    since: "14.1",
                    message: "Use the 'value' option instead."
                }},
            _optionAliases: {checked: "value"},
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    value: undefined,
                    valueChangeAction: null
                })
            },
            _init: function() {
                this.callBase();
                this._feedbackHideTimeout = CHECKBOX_FEEDBACK_HIDE_TIMEOUT
            },
            _render: function() {
                this.callBase();
                this._element().addClass(CHECKBOX_CLASS);
                this._$iconContainer = $("<span />");
                this._$iconContainer.addClass(CHECKBOX_ICON_CLASS).appendTo(this._element());
                this._renderValue();
                this._renderClick();
                this._updateContentSize()
            },
            _renderDimensions: function() {
                this.callBase();
                this._updateContentSize()
            },
            _updateContentSize: function() {
                var $element = this._element(),
                    width = this.option("width"),
                    height = this.option("height");
                if (this._$iconContainer && (width || height)) {
                    width = this._element().width();
                    height = this._element().height();
                    var minDimention = Math.min(height, width);
                    this._$iconContainer.css({
                        height: minDimention,
                        width: minDimention,
                        "margin-top": (height - minDimention) / 2,
                        "margin-left": (width - minDimention) / 2
                    })
                }
            },
            _renderClick: function() {
                var clickAction = this._createAction(this._handleClick);
                this._element().off(CHECKBOX_DXCLICK_EVENT_NAME).on(CHECKBOX_DXCLICK_EVENT_NAME, function(e) {
                    clickAction({jQueryEvent: e})
                })
            },
            _handleClick: function(args) {
                var that = args.component;
                that._valueChangeEventInstance = args.jQueryEvent;
                that.option("value", !that.option("value"))
            },
            _renderValue: function() {
                var $element = this._element(),
                    checked = this.option("value"),
                    indeterminate = checked === undefined;
                $element.toggleClass(CHECKBOX_CHECKED_CLASS, Boolean(checked));
                $element.toggleClass(CHECKBOX_INDETERMINATE_CLASS, indeterminate)
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"value":
                        this._renderValue();
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.textEditor.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var TEXTEDITOR_CLASS = "dx-texteditor",
            TEXTEDITOR_INPUT_CLASS = "dx-texteditor-input",
            TEXTEDITOR_INPUT_SELECTOR = "." + TEXTEDITOR_INPUT_CLASS,
            TEXTEDITOR_BORDER_CLASS = "dx-texteditor-border",
            TEXTEDITOR_PLACEHOLDER_CLASS = "dx-placeholder",
            TEXTEDITOR_SHOW_CLEAR_BUTTON_CLASS = "dx-show-clear-button",
            TEXTEDITOR_CLEAR_ICON_CLASS = "dx-icon-clear",
            TEXTEDITOR_CLEAR_BUTTON_CLASS = "dx-clear-button-area",
            TEXTEDITOR_EMPTY_INPUT_CLASS = "dx-texteditor-empty",
            TEXTEDITOR_STATE_FOCUSED_CLASS = "dx-state-focused",
            EVENTS_LIST = ["focusIn", "focusOut", "keyDown", "keyPress", "keyUp", "change", "cut", "copy", "paste", "input"];
        var nativePlaceholderSupport = function() {
                var check = document.createElement("input");
                return "placeholder" in check
            }();
        DX.registerComponent("dxTextEditor", ui.dxEditor.inherit({
            _deprecatedOptions: {
                valueUpdateEvent: {
                    since: "14.1",
                    message: "Use the 'valueChangeEvent' option instead."
                },
                valueUpdateAction: {
                    since: "14.1",
                    message: "Use the 'valueChangeAction' option instead."
                }
            },
            _optionAliases: {valueUpdateEvent: "valueChangeEvent"},
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    value: "",
                    showClearButton: false,
                    valueChangeEvent: "change",
                    valueUpdateAction: null,
                    placeholder: "",
                    readOnly: false,
                    focusInAction: null,
                    focusOutAction: null,
                    keyDownAction: null,
                    keyPressAction: null,
                    keyUpAction: null,
                    changeAction: null,
                    inputAction: null,
                    cutAction: null,
                    copyAction: null,
                    pasteAction: null,
                    enterKeyAction: null,
                    mode: "text",
                    activeStateEnabled: false
                })
            },
            _input: function() {
                return this._element().find(TEXTEDITOR_INPUT_SELECTOR)
            },
            _render: function() {
                this._element().addClass(TEXTEDITOR_CLASS);
                this._renderInput();
                this._renderInputType();
                this._renderValue();
                this._renderProps();
                this._renderPlaceholder();
                this._renderEvents();
                this._toggleClearButton();
                this._renderEnterKeyAction();
                this._renderEmptinessEvent();
                this._renderFocusEvent();
                this.callBase()
            },
            _renderInput: function(inputContainer) {
                (inputContainer || this._element()).append($("<div>").addClass(TEXTEDITOR_BORDER_CLASS).append($("<input>").addClass(TEXTEDITOR_INPUT_CLASS)))
            },
            _renderValue: function(formattedValue) {
                var text = formattedValue || this.option("value");
                if (this._input().val() !== text) {
                    this._input().val(text);
                    this._togglePlaceholderVisibility(text === "" || text === null)
                }
            },
            _togglePlaceholderVisibility: function(visibility) {
                this._element().toggleClass(TEXTEDITOR_EMPTY_INPUT_CLASS, visibility);
                this._$placeholder && this._$placeholder.toggle(visibility)
            },
            _renderProps: function() {
                this._input().prop({
                    readOnly: this._readOnlyPropValue(),
                    disabled: this.option("disabled")
                })
            },
            _readOnlyPropValue: function() {
                return this.option("readOnly")
            },
            _renderPlaceholder: function() {
                var that = this,
                    $input = that._input(),
                    placeholderText = that.option("placeholder"),
                    $placeholder = this._$placeholder = $('<div>').attr("data-dx_placeholder", placeholderText),
                    startEvent = events.addNamespace("dxclick", this.NAME);
                $placeholder.on(startEvent, function() {
                    $input.focus()
                });
                $placeholder.appendTo($input.parent());
                $placeholder.addClass(TEXTEDITOR_PLACEHOLDER_CLASS)
            },
            _toggleClearButton: function() {
                if (!nativePlaceholderSupport)
                    return;
                var $element = this._element(),
                    showing = this.option("showClearButton") && !this.option("readOnly");
                $element.toggleClass(TEXTEDITOR_SHOW_CLEAR_BUTTON_CLASS, showing);
                if (showing)
                    this._renderClearButton();
                else
                    this._$clearButton && this._$clearButton.remove()
            },
            _renderClearButton: function() {
                var $clearButton = $("<span>").addClass(TEXTEDITOR_CLEAR_BUTTON_CLASS).append($("<span>").addClass(TEXTEDITOR_CLEAR_ICON_CLASS)).on("dxclick", $.proxy(this._handleClearValue, this));
                this._element().append($clearButton);
                this._$clearButton = $clearButton
            },
            _handleClearValue: function() {
                this.option("value", "")
            },
            _renderEvents: function() {
                var that = this,
                    $input = that._input();
                that._renderValueUpdateEvent();
                $.each(EVENTS_LIST, function(_, event) {
                    var eventName = events.addNamespace(event.toLowerCase(), that.NAME),
                        action = that._createActionByOption(event + "Action");
                    $input.off(eventName).on(eventName, function(e) {
                        action({jQueryEvent: e})
                    })
                })
            },
            _renderValueUpdateEvent: function() {
                var eventNamespace = this.NAME + "ValueUpdate";
                var valueChangeEvent = events.addNamespace(this.option("valueChangeEvent"), eventNamespace);
                this._input().off("." + eventNamespace).on(valueChangeEvent, $.proxy(this._handleValueChangeEvent, this));
                this._valueUpdateAction = this._createActionByOption("valueUpdateAction")
            },
            _renderFocusEvent: function() {
                var $element = this._element();
                $element.find("." + TEXTEDITOR_INPUT_CLASS).focusin(function() {
                    $element.addClass(TEXTEDITOR_STATE_FOCUSED_CLASS)
                }).focusout(function() {
                    $element.removeClass(TEXTEDITOR_STATE_FOCUSED_CLASS)
                }).filter(":focus").addClass(TEXTEDITOR_STATE_FOCUSED_CLASS)
            },
            _renderEmptinessEvent: function() {
                var $input = this._input();
                $input.on("input keyup blur", $.proxy(this._toggleEmptinessEventHandler, this));
                this._toggleEmptinessEventHandler()
            },
            _toggleEmptinessEventHandler: function() {
                var value = this._input().val();
                this._togglePlaceholderVisibility(value === "" || value === null)
            },
            _handleValueChangeEvent: function(e, formattedValue) {
                this._valueChangeEventInstance = e;
                this._suppressValueUpdateAction = true;
                this.option("value", arguments.length > 1 ? formattedValue : this._input().val());
                this._suppressValueUpdateAction = false;
                this._valueUpdateAction({
                    value: this.option("value"),
                    jQueryEvent: e
                })
            },
            _renderEnterKeyAction: function() {
                if (this.option("enterKeyAction")) {
                    this._enterKeyAction = this._createActionByOption("enterKeyAction");
                    this._input().on("keyup.enterKey.dxTextEditor", $.proxy(this._handleEnterKeyUp, this))
                }
                else {
                    this._input().off("keyup.enterKey.dxTextEditor");
                    this._enterKeyAction = undefined
                }
            },
            _handleEnterKeyUp: function(e) {
                if (e.which === 13)
                    this._enterKeyAction({jQueryEvent: e})
            },
            _toggleDisabledState: function() {
                this.callBase.apply(this, arguments);
                this._renderProps()
            },
            _updateValue: function() {
                this._renderValue();
                if (!this._suppressValueUpdateAction)
                    this._valueUpdateAction({value: this.option("value")})
            },
            _suppressUpdateValue: function() {
                this._valueUpdateSuppressed = true
            },
            _resumeUpdateValue: function() {
                this._valueUpdateSuppressed = false
            },
            _optionChanged: function(optionName) {
                if ($.inArray(optionName.replace("Action", ""), EVENTS_LIST) > -1) {
                    this._renderEvents();
                    return
                }
                switch (optionName) {
                    case"valueChangeEvent":
                    case"valueUpdateAction":
                        this._renderValueUpdateEvent();
                        break;
                    case"readOnly":
                        this._renderProps();
                        this._toggleClearButton();
                        break;
                    case"mode":
                        this._renderInputType();
                        break;
                    case"enterKeyAction":
                        this._renderEnterKeyAction();
                        break;
                    case"placeholder":
                        this._invalidate();
                        break;
                    case"showClearButton":
                        this._toggleClearButton();
                        break;
                    case"value":
                        if (!this._valueUpdateSuppressed)
                            this._updateValue();
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _renderInputType: function() {
                this._setInputType(this.option("mode"))
            },
            _setInputType: function(type) {
                var input = this._input();
                try {
                    input.prop("type", type)
                }
                catch(e) {
                    input.prop("type", "text")
                }
            },
            focus: function() {
                this._input().focus()
            },
            blur: function() {
                if (this._input().is(document.activeElement))
                    DX.utils.resetActiveElement()
            }
        }));
        ui.dxTextEditor.__internals = {nativePlaceholderSupport: function(newState) {
                if (arguments.length)
                    nativePlaceholderSupport = !!newState;
                return nativePlaceholderSupport
            }}
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.textBox.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            devices = DX.devices,
            ua = window.navigator.userAgent,
            ignoreCode = [8, 9, 13, 33, 34, 35, 36, 37, 38, 39, 40, 46],
            TEXTBOX_CLASS = "dx-textbox",
            SEARCHBOX_CLASS = "dx-searchbox",
            SEARCH_ICON_CLASS = "dx-icon-search";
        DX.registerComponent("dxTextBox", ui.dxTextEditor.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    mode: "text",
                    maxLength: null
                })
            },
            _render: function() {
                this.callBase();
                this._element().addClass(TEXTBOX_CLASS);
                this._renderMaxLengthHandlers();
                this._renderSearchMode()
            },
            _renderMaxLengthHandlers: function() {
                if (this._isAndroid())
                    this._input().on(events.addNamespace("keydown", this.NAME), $.proxy(this._onKeyDownAndroidHandler, this)).on(events.addNamespace("change", this.NAME), $.proxy(this._onChangeAndroidHandler, this))
            },
            _renderProps: function() {
                this.callBase();
                if (this._isAndroid())
                    return;
                var maxLength = this.option("maxLength");
                if (maxLength > 0)
                    this._input().prop("maxLength", maxLength)
            },
            _renderSearchMode: function() {
                var $element = this._$element;
                if (this.option("mode") === "search") {
                    this._renderSearchIcon();
                    $element.addClass(SEARCHBOX_CLASS);
                    this._showClearButton = this.option("showClearButton");
                    this.option("showClearButton", true)
                }
                if (this.option("mode") !== "search") {
                    $element.removeClass(SEARCHBOX_CLASS);
                    this._$searchIcon && this._$searchIcon.remove();
                    this.option("showClearButton", this._showClearButton === undefined ? this.option("showClearButton") : this._showClearButton)
                }
            },
            _renderSearchIcon: function() {
                var $searchIcon = $("<div>").addClass(SEARCH_ICON_CLASS);
                $searchIcon.prependTo(this._input().parent());
                this._$searchIcon = $searchIcon
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"maxLength":
                        this._renderProps();
                        this._renderMaxLengthHandlers();
                        break;
                    case"mode":
                        this._renderSearchMode();
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _onKeyDownAndroidHandler: function(e) {
                var maxLength = this.option("maxLength");
                if (maxLength) {
                    var $input = $(e.target),
                        code = e.keyCode;
                    this._cutOffExtraChar($input);
                    return $input.val().length < maxLength || $.inArray(code, ignoreCode) !== -1 || window.getSelection().toString() !== ""
                }
                else
                    return true
            },
            _onChangeAndroidHandler: function(e) {
                var $input = $(e.target);
                if (this.option("maxLength"))
                    this._cutOffExtraChar($input)
            },
            _cutOffExtraChar: function($input) {
                var maxLength = this.option("maxLength"),
                    textInput = $input.val();
                if (textInput.length > maxLength)
                    $input.val(textInput.substr(0, maxLength))
            },
            _isAndroid: function() {
                var realDevice = devices.real();
                var version = realDevice.version.join(".");
                return realDevice.platform === "android" && version && /^(2\.|4\.1)/.test(version) && !/chrome/i.test(ua)
            }
        }));
        ui.dxTextBox.__internals = {
            uaAccessor: function(value) {
                if (!arguments.length)
                    return ui;
                ua = value
            },
            SEARCHBOX_CLASS: SEARCHBOX_CLASS,
            SEARCH_ICON_CLASS: SEARCH_ICON_CLASS
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.dropDownEditor.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            DROP_DOWN_EDITOR_CLASS = "dx-dropdowneditor",
            DROP_DOWN_EDITOR_READONLY_CLASS = "dx-dropdowneditor-readonly",
            DROP_DOWN_EDITOR_INPUT_WRAPPER_CLASS = "dx-dropdowneditor-input-wrapper",
            DROP_DOWN_EDITOR_BUTTON_CLASS = "dx-dropdowneditor-button",
            DROP_DOWN_EDITOR_BUTTON_ICON = "dx-dropdowneditor-icon",
            DROP_DOWN_EDITOR_OVERLAY = "dx-dropdowneditor-overlay",
            DROP_DOWN_EDITOR_ACTIVE = "dx-dropdowneditor-active",
            DROP_DOWN_EDITOR_BUTTON_VISIBLE = "dx-dropdowneditor-button-visible",
            DROP_DOWN_EDITOR_DXCLICK_EVENT_NAME = events.addNamespace("dxclick", "dxDropDownEditor"),
            DROP_DOWN_EDITOR_MOUSE_DOWN_EVENT_NAME = events.addNamespace("mousedown", "dxDropDownEditor"),
            keyboardKeys = {
                upArrow: 38,
                downArrow: 40
            };
        DX.registerComponent("dxDropDownEditor", ui.dxTextBox.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    openAction: null,
                    closeAction: null
                })
            },
            open: function() {
                this._showDropDown()
            },
            close: function() {
                this._hideDropDown()
            },
            _clean: function() {
                this.callBase();
                if (this._dropDownContainer) {
                    this._dropDownContainer.remove();
                    this._dropDown = undefined
                }
            },
            _render: function() {
                this._dropDownContainerRendered = false;
                this._element().addClass(DROP_DOWN_EDITOR_CLASS);
                this._renderButton();
                this.callBase();
                this._renderKeyboardEvents();
                var that = this;
                this._input().on("blur", function(e) {
                    if (that._hideOnBlur() && !that._needToPreventBlur)
                        that._hideDropDown();
                    that._needToPreventBlur = false
                })
            },
            _renderInput: function(inputContainer) {
                this._inputWrapper = inputContainer || $("<div>");
                this._inputWrapper.addClass(DROP_DOWN_EDITOR_INPUT_WRAPPER_CLASS);
                this._element().prepend(this._inputWrapper);
                this.callBase(this._inputWrapper)
            },
            _renderButton: function(hideButton) {
                this._button = $("<div>").addClass(DROP_DOWN_EDITOR_BUTTON_CLASS);
                this._attachButtonEvents();
                this._updateButtonReadonlyState();
                this._buttonIcon = $("<div>").addClass(DROP_DOWN_EDITOR_BUTTON_ICON).appendTo(this._button);
                this._button.appendTo(this._element());
                if (hideButton) {
                    this._element().removeClass(DROP_DOWN_EDITOR_BUTTON_VISIBLE);
                    this._button.hide()
                }
                else
                    this._element().addClass(DROP_DOWN_EDITOR_BUTTON_VISIBLE)
            },
            _attachButtonEvents: function() {
                var that = this,
                    dxClickAction,
                    mouseDownAction;
                this._button.off(DROP_DOWN_EDITOR_DXCLICK_EVENT_NAME).off(DROP_DOWN_EDITOR_MOUSE_DOWN_EVENT_NAME);
                if (!this.option("readOnly")) {
                    dxClickAction = this._createAction(function() {
                        that._toggleDropDown();
                        that._dropDownClickHandler()
                    });
                    mouseDownAction = this._createAction(function(args) {
                        that._mouseDownFocusKeeper(args.jQueryEvent)
                    });
                    this._button.on(DROP_DOWN_EDITOR_DXCLICK_EVENT_NAME, function() {
                        dxClickAction()
                    }).on(DROP_DOWN_EDITOR_MOUSE_DOWN_EVENT_NAME, function(e) {
                        mouseDownAction({jQueryEvent: e})
                    })
                }
            },
            _updateButtonReadonlyState: function() {
                this._button.removeClass(DROP_DOWN_EDITOR_READONLY_CLASS);
                if (this.option("readOnly"))
                    this._button.addClass(DROP_DOWN_EDITOR_READONLY_CLASS)
            },
            _renderKeyboardEvents: function() {
                this._input().off(events.addNamespace("keydown", "dxDropDownEditor")).on(events.addNamespace("keydown", "dxDropDownEditor"), $.proxy(this._onKeyDownHandler, this))
            },
            _dropDownClickHandler: function() {
                if (!this._deviceHasTouchScreen() && !this._input().is(":focus"))
                    this.focus();
                this._needToPreventBlur = false
            },
            _mouseDownFocusKeeper: function(e) {
                this._needToPreventBlur = true;
                if (e && e.preventDefault)
                    e.preventDefault()
            },
            _deviceHasTouchScreen: function() {
                var device = DevExpress.devices.real();
                return DevExpress.support.touch || device.platform === "win8" && (device.phone || device.tablet)
            },
            _hideOnBlur: function() {
                return true
            },
            _renderDropDownContent: function() {
                return []
            },
            _dropDownVisible: function() {
                return this._dropDown && this._dropDown.option("visible")
            },
            _toggleDropDown: function() {
                this._dropDownVisible() ? this._hideDropDown() : this._showDropDown()
            },
            _showDropDown: function() {
                if (!this._dropDownVisible()) {
                    this._renderDropDownContainer();
                    this._dropDown.show();
                    this._element().addClass(DROP_DOWN_EDITOR_ACTIVE)
                }
            },
            _hideDropDown: function() {
                if (this._dropDownVisible()) {
                    this._element().removeClass(DROP_DOWN_EDITOR_ACTIVE);
                    this._dropDown.hide()
                }
            },
            _renderDropDownContainer: function() {
                var that = this,
                    dropDownContent;
                if (!this._dropDownContainerRendered) {
                    this._dropDownContainer = $("<div>").addClass(DROP_DOWN_EDITOR_OVERLAY).addClass(that.option("customOverlayCssClass"));
                    this._element().append(this._dropDownContainer);
                    this._createDropDown();
                    dropDownContent = this._renderDropDownContent();
                    if (!$.isArray(dropDownContent))
                        dropDownContent = [dropDownContent];
                    $.each(dropDownContent, function(index, contentElement) {
                        contentElement.off(DROP_DOWN_EDITOR_MOUSE_DOWN_EVENT_NAME).on(DROP_DOWN_EDITOR_MOUSE_DOWN_EVENT_NAME, function(e) {
                            that._mouseDownFocusKeeper(e)
                        }).off(DROP_DOWN_EDITOR_DXCLICK_EVENT_NAME).on(DROP_DOWN_EDITOR_DXCLICK_EVENT_NAME, function() {
                            that._dropDownClickHandler()
                        });
                        that._dropDownContainer.append(contentElement)
                    });
                    this._dropDownContainerRendered = true
                }
            },
            _createDropDown: function(options) {
                this._dropDown = this._dropDownContainer.dxOverlay($.extend(true, {
                    position: {
                        offset: "0 -1",
                        my: "left top",
                        at: "left bottom",
                        of: this._element(),
                        collision: "flip flip"
                    },
                    showTitle: false,
                    width: "auto",
                    height: "auto",
                    shading: false,
                    rtlEnabled: this.option("rtlEnabled"),
                    closeOnTargetScroll: $.proxy(this._closeOnScrollHandler, this),
                    closeOnOutsideClick: $.proxy(this._closeOutsideDropDownHandler, this),
                    animation: {
                        show: false,
                        hide: false
                    },
                    shownAction: this.option("openAction"),
                    hiddenAction: this.option("closeAction")
                }, options)).dxOverlay("instance")
            },
            _closeOnScrollHandler: function(e) {
                this._hideDropDown();
                return true
            },
            _closeOutsideDropDownHandler: function(e, ignoreContainerClicks) {
                if (e.target !== this._input()[0] && e.target !== this._button[0] && !this._button.find($(e.target)).length && (!ignoreContainerClicks || !this._dropDown._container().find($(e.target)).length))
                    this._hideDropDown();
                return false
            },
            _onKeyDownHandler: function(e) {
                if (e.altKey) {
                    if (e.which === keyboardKeys.downArrow)
                        this._showDropDown();
                    if (e.which === keyboardKeys.upArrow)
                        this._hideDropDown()
                }
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"rtlEnabled":
                        this.callBase.apply(this, arguments);
                        if (this._dropDownContainerRendered)
                            this._dropDown.option(name, value);
                        break;
                    case"openAction":
                        if (this._dropDownContainerRendered)
                            this._dropDown.option("shownAction", value);
                        break;
                    case"closeAction":
                        if (this._dropDownContainerRendered)
                            this._dropDown.option("hiddenAction", value);
                        break;
                    case"readOnly":
                        this._attachButtonEvents();
                        this._updateButtonReadonlyState();
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        ui.dxDropDownEditor.__internals = {
            DROP_DOWN_EDITOR_CLASS: DROP_DOWN_EDITOR_CLASS,
            DROP_DOWN_EDITOR_READONLY_CLASS: DROP_DOWN_EDITOR_READONLY_CLASS,
            DROP_DOWN_EDITOR_BUTTON_ICON: DROP_DOWN_EDITOR_BUTTON_ICON,
            DROP_DOWN_EDITOR_INPUT_WRAPPER_CLASS: DROP_DOWN_EDITOR_INPUT_WRAPPER_CLASS,
            DROP_DOWN_EDITOR_BUTTON_CLASS: DROP_DOWN_EDITOR_BUTTON_CLASS,
            DROP_DOWN_EDITOR_OVERLAY: DROP_DOWN_EDITOR_OVERLAY,
            DROP_DOWN_EDITOR_ACTIVE: DROP_DOWN_EDITOR_ACTIVE,
            DROP_DOWN_EDITOR_BUTTON_VISIBLE: DROP_DOWN_EDITOR_BUTTON_VISIBLE
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.textArea.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var TEXTAREA_CLASS = "dx-textarea",
            TEXTEDITOR_INPUT_CLASS = "dx-texteditor-input",
            TEXTEDITOR_BORDER_CLASS = "dx-texteditor-border";
        DX.registerComponent("dxTextArea", ui.dxTextBox.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({})
            },
            _render: function() {
                this.callBase();
                this._element().addClass(TEXTAREA_CLASS)
            },
            _renderInput: function() {
                this._element().append($("<div />").addClass(TEXTEDITOR_BORDER_CLASS).append($("<textarea />").addClass(TEXTEDITOR_INPUT_CLASS)));
                this._renderScrollHandler()
            },
            _renderScrollHandler: function() {
                var $input = this._input(),
                    eventY = 0;
                $input.on(events.addNamespace("dxpointerdown", this.NAME), function(e) {
                    eventY = events.eventData(e).y
                });
                $input.on(events.addNamespace("dxpointermove", this.NAME), function(e) {
                    var scrollTopPos = $input.scrollTop(),
                        scrollBottomPos = $input.prop("scrollHeight") - $input.prop("clientHeight") - scrollTopPos;
                    if (scrollTopPos === 0 && scrollBottomPos === 0)
                        return;
                    var currentEventY = events.eventData(e).y;
                    var isScrollFromTop = scrollTopPos === 0 && eventY >= currentEventY,
                        isScrollFromBottom = scrollBottomPos === 0 && eventY <= currentEventY,
                        isScrollFromMiddle = scrollTopPos > 0 && scrollBottomPos > 0;
                    if (isScrollFromTop || isScrollFromBottom || isScrollFromMiddle)
                        e.originalEvent.isScrollingEvent = true;
                    eventY = currentEventY
                })
            },
            _renderInputType: $.noop
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.numberBox.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            math = Math,
            events = ui.events,
            WIDGET_CLASS = "dx-numberbox",
            SPIN_CLASS = WIDGET_CLASS + "-spin",
            SPIN_CONTAINER_CLASS = SPIN_CLASS + "-container",
            SPIN_UP_CLASS = SPIN_CLASS + "-up",
            SPIN_DOWN_CLASS = SPIN_CLASS + "-down",
            SPIN_BUTTON_CLASS = SPIN_CLASS + "-button",
            SPIN_UP_SELECTOR = "." + SPIN_UP_CLASS,
            SPIN_DOWN_SELECTOR = "." + SPIN_DOWN_CLASS,
            SPIN_HOLD_DELAY = 150;
        DX.registerComponent("dxSpinButton", ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    direction: "up",
                    changeAction: null
                })
            },
            _render: function() {
                this.callBase();
                var that = this,
                    $element = this._element(),
                    pointerDownEvent = events.addNamespace("dxpointerdown", this.NAME),
                    direction = SPIN_CLASS + "-" + this.option("direction");
                $element.addClass(SPIN_BUTTON_CLASS).addClass(direction).off(pointerDownEvent).on(pointerDownEvent, $.proxy(this._handleSpinHold, this));
                this._spinIcon = $("<div>").addClass(direction + "-icon").appendTo(this._element());
                this._handleSpinChange = this._createActionByOption("changeAction")
            },
            _handleSpinHold: function(e) {
                var pointerUpEvent = events.addNamespace("dxpointerup", this.NAME),
                    pointerCancelEvent = events.addNamespace("dxpointercancel", this.NAME);
                this._clearTimer();
                $(document).off(pointerUpEvent).off(pointerCancelEvent).on(pointerUpEvent, $.proxy(this._clearTimer, this)).on(pointerCancelEvent, $.proxy(this._clearTimer, this));
                this._handleSpinChange({jQueryEvent: e});
                this._holdTimer = setInterval(this._handleSpinChange, SPIN_HOLD_DELAY, {jQueryEvent: e})
            },
            _dispose: function() {
                this._clearTimer();
                this.callBase()
            },
            _clearTimer: function(e) {
                if (this._holdTimer)
                    clearInterval(this._holdTimer)
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"changeAction":
                    case"direction":
                        this._invalidate();
                        break;
                    default:
                        this.callBase(name, value, prevValue)
                }
            }
        }));
        DX.registerComponent("dxNumberBox", ui.dxTextEditor.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    value: 0,
                    min: undefined,
                    max: undefined,
                    mode: "tel",
                    showSpinButtons: false,
                    step: 1
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function(device) {
                                var realDevice = DX.devices.real(),
                                    realPlatform = realDevice.platform,
                                    realVersion = realDevice.version;
                                var isDesktop = realDevice.deviceType === "desktop",
                                    isNewIE = DX.browser["msie"] && DX.browser.version.split(".")[0] > 9 && isDesktop,
                                    isChrome = DX.browser["webkit"] && isDesktop,
                                    isMozilla = DX.browser["mozilla"] && isDesktop,
                                    isAndroid44 = realPlatform === "android" && realVersion[0] >= 4 && realVersion[1] >= 4,
                                    isIos7 = realPlatform === "ios" && realVersion[0] > 6;
                                return isNewIE || isChrome || isIos7 || isAndroid44 || isMozilla
                            },
                            options: {mode: "number"}
                        }])
            },
            _init: function() {
                this.callBase();
                this._initSpinButtons()
            },
            _initSpinButtons: function() {
                this._$spinContainer = $("<div>").addClass(SPIN_CONTAINER_CLASS);
                this._$spinUp = $("<div>").dxSpinButton({
                    direction: "up",
                    changeAction: $.proxy(this._handleSpinUpChange, this)
                }).appendTo(this._$spinContainer);
                this._$spinDown = $("<div>").dxSpinButton({
                    direction: "down",
                    changeAction: $.proxy(this._handleSpinDownChange, this)
                }).appendTo(this._$spinContainer)
            },
            _render: function() {
                this.callBase();
                this._element().addClass(WIDGET_CLASS);
                this._renderSpinButtons()
            },
            _renderSpinButtons: function() {
                this._element().toggleClass(SPIN_CLASS, this.option("showSpinButtons"));
                if (this.option("showSpinButtons"))
                    this._$spinContainer.appendTo(this._element());
                else
                    this._$spinContainer.detach()
            },
            _handleSpinUpChange: function() {
                var value = parseFloat(this.option().value),
                    step = parseFloat(this.option().step);
                this.option("value", value + step)
            },
            _handleSpinDownChange: function() {
                var value = parseFloat(this.option().value),
                    step = parseFloat(this.option().step);
                this.option("value", value - step)
            },
            _renderValue: function() {
                var value = this.option("value") ? this.option("value").toString() : this.option("value");
                if (this._input().val() !== value) {
                    var inputType = this._input().attr("type");
                    this._setInputType("text");
                    this._input().val(this.option("value"));
                    this._setInputType(inputType);
                    this._togglePlaceholderVisibility(value === "" || value === null)
                }
            },
            _renderProps: function() {
                this.callBase();
                this._input().prop({
                    min: this.option("min"),
                    max: this.option("max"),
                    step: this.option("step")
                })
            },
            _trimInputValue: function() {
                var $input = this._input(),
                    value = $.trim($input.val());
                if (value[value.length - 1] === ".")
                    value = value.slice(0, -1);
                this._forceRefreshInputValue(value)
            },
            _inputInvalidHandler: function() {
                var $input = this._input(),
                    value = $input.val();
                if (this._oldValue) {
                    this.option("value", this._oldValue);
                    $input.val(this._oldValue);
                    this._oldValue = null;
                    return
                }
                this.option("value", "");
                $input.val("")
            },
            _forceRefreshInputValue: function(value) {
                var $input = this._input();
                $input.val("").val(value)
            },
            _handleValueChangeEvent: function(e) {
                var $input = this._input(),
                    value = $.trim($input.val()),
                    input = $input.get(0);
                if (typeof input.checkValidity === "function")
                    input.checkValidity();
                value = value.replace(",", ".");
                $input.focusout($.proxy(this._trimInputValue, this)).on("invalid", $.proxy(this._inputInvalidHandler, this));
                if (!this._validateValue(value)) {
                    this._inputInvalidHandler();
                    return
                }
                value = this._parseValue(value);
                if (!value && value !== 0)
                    return;
                this.callBase(e, value);
                if ($input.val() != value)
                    $input.val(value)
            },
            _validateValue: function(value) {
                this._oldValue = this.option("value");
                if (!value) {
                    this.option("value", "");
                    return true
                }
                var isNumber = /^-?\d+\.?\d*$/.test(value),
                    isExponent = /^-?\d+e[-+]?\d+$/.test(value);
                if (!isNumber && !isExponent)
                    return false;
                return true
            },
            _parseValue: function(value) {
                var number = parseFloat(value);
                if (this.option("min") !== undefined)
                    number = math.max(number, this.option("min"));
                if (this.option("max") !== undefined)
                    number = math.min(number, this.option("max"));
                return number
            },
            _setValue: function(value, prevValue) {
                if (value === prevValue)
                    return;
                if (!value && value !== 0) {
                    this.option("value", "");
                    return
                }
                if ($.type(value) === "string")
                    value = value.replace(",", ".");
                value = this._parseValue(value);
                if (!value && value !== 0) {
                    this.option("value", prevValue);
                    return
                }
                this.option("value", value)
            },
            _renderPlaceholder: function() {
                if (this.option("mode") === "number")
                    this._input().attr("placeholder", this.option("placeholder"));
                else
                    this.callBase()
            },
            _invalidate: function() {
                this._$spinContainer.detach();
                this.callBase()
            },
            _dispose: function() {
                this._$spinContainer.remove()
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"value":
                        this._setValue(value, prevValue);
                        this.callBase.apply(this, arguments);
                        break;
                    case"step":
                    case"min":
                    case"max":
                        this._renderProps();
                        break;
                    case"showSpinButtons":
                        this._renderSpinButtons();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        ui.dxNumberBox.__internals = {
            WIDGET_CLASS: WIDGET_CLASS,
            SPIN_CLASS: SPIN_CLASS,
            SPIN_CONTAINER_CLASS: SPIN_CONTAINER_CLASS,
            SPIN_UP_CLASS: SPIN_UP_CLASS,
            SPIN_DOWN_CLASS: SPIN_DOWN_CLASS
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.radioButton.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var RADIO_BUTTON = "dxRadioButton",
            RADIO_BUTTON_CLASS = "dx-radio-button",
            RADIO_BUTTON_ICON_CLASS = "dx-radio-button-icon",
            RADIO_BUTTON_CHECKED_CLASS = "dx-radio-button-checked",
            RADIO_BUTTON_DXCLICK_EVENT_NAME = events.addNamespace("dxclick", RADIO_BUTTON);
        DX.registerComponent(RADIO_BUTTON, ui.dxEditor.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({value: false})
            },
            _init: function() {
                this.callBase();
                this._element().addClass(RADIO_BUTTON_CLASS)
            },
            _render: function() {
                this.callBase();
                this._renderIcon();
                this._renderCheckedState(this.option("value"));
                this._renderClick()
            },
            _renderIcon: function() {
                var $icon = $("<div />").addClass(RADIO_BUTTON_ICON_CLASS);
                this._element().append($icon)
            },
            _renderCheckedState: function(checked) {
                this._element().toggleClass(RADIO_BUTTON_CHECKED_CLASS, checked)
            },
            _renderClick: function() {
                var clickAction = this._createAction($.proxy(function(args) {
                        this._handleClick(args.jQueryEvent)
                    }, this));
                this._element().off(RADIO_BUTTON_DXCLICK_EVENT_NAME).on(RADIO_BUTTON_DXCLICK_EVENT_NAME, function(e) {
                    clickAction({jQueryEvent: e})
                })
            },
            _handleClick: function(e) {
                this._valueChangeEventInstance = e;
                this.option("value", true)
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"value":
                        this._renderCheckedState(value);
                        this.callBase.apply(this, arguments);
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.radioGroup.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var RADIO_GROUP_CLASS = "dx-radio-group",
            RADIO_GROUP_VERTICAL_CLASS = "dx-radio-group-vertical",
            RADIO_GROUP_HORIZONTAL_CLASS = "dx-radio-group-horizontal",
            RADIO_BUTTON_CLASS = "dx-radio-button",
            RADIO_BUTTON_ICON_CLASS = "dx-radio-button-icon",
            RADIO_VALUE_CONTAINER_CLASS = "dx-radio-value-container",
            RADIO_BUTTON_CHECKED_CLASS = "dx-radio-button-checked",
            RADIO_BUTTON_DATA_KEY = "dxRadioButtonData",
            RADIO_FEEDBACK_HIDE_TIMEOUT = 100;
        DX.registerComponent("dxRadioGroup", ui.CollectionContainerWidget.inherit({
            _activeStateUnit: "." + RADIO_BUTTON_CLASS,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    layout: "vertical",
                    value: undefined,
                    valueExpr: null
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: {tablet: true},
                            options: {layout: "horizontal"}
                        }])
            },
            _optionsByReference: function() {
                return $.extend(this.callBase(), {value: true})
            },
            _itemClass: function() {
                return RADIO_BUTTON_CLASS
            },
            _itemDataKey: function() {
                return RADIO_BUTTON_DATA_KEY
            },
            _itemContainer: function() {
                return this._element()
            },
            _init: function() {
                this.callBase();
                if (!this._dataSource)
                    this._itemsToDataSource();
                this._feedbackHideTimeout = RADIO_FEEDBACK_HIDE_TIMEOUT
            },
            _itemsToDataSource: function() {
                this._dataSource = new DevExpress.data.DataSource(this.option("items"))
            },
            _render: function() {
                this._element().addClass(RADIO_GROUP_CLASS);
                this._compileValueGetter();
                this.callBase();
                this._renderLayout();
                this._renderValue();
                this._updateContentSize()
            },
            _renderDimensions: function() {
                this.callBase();
                this._updateContentSize()
            },
            _updateContentSize: function() {
                if (this.option("layout") === "horizontal")
                    this._itemElements().css("height", "auto");
                else {
                    var itemsCount = this.option("items").length;
                    this._itemElements().css("height", 100 / itemsCount + "%")
                }
            },
            _compileValueGetter: function() {
                this._valueGetter = DX.data.utils.compileGetter(this._valueGetterExpr())
            },
            _valueGetterExpr: function() {
                return this.option("valueExpr") || this._dataSource && this._dataSource._store._key || "this"
            },
            _renderLayout: function() {
                var layout = this.option("layout");
                this._element().toggleClass(RADIO_GROUP_VERTICAL_CLASS, layout === "vertical");
                this._element().toggleClass(RADIO_GROUP_HORIZONTAL_CLASS, layout === "horizontal")
            },
            _renderValue: function() {
                var value = this.option("value");
                value != null && value !== undefined ? this._setIndexByValue() : this._setValueByIndex()
            },
            _setIndexByValue: function(value) {
                var that = this;
                value = value === undefined ? that.option("value") : value;
                that._searchValue(value).done(function(item) {
                    if (that._dataSource.isLoaded())
                        that._setIndexByItem(item);
                    else
                        that._dataSource.load().done(function() {
                            that._setIndexByItem(item)
                        })
                })
            },
            _setIndexByItem: function(item) {
                this.option("selectedIndex", $.inArray(item, this._dataSource.items()))
            },
            _searchValue: function(value) {
                var that = this,
                    store = that._dataSource.store(),
                    valueExpr = that._valueGetterExpr();
                var deffered = $.Deferred();
                if (valueExpr === store.key() || store instanceof DX.data.CustomStore)
                    store.byKey(value).done(function(result) {
                        deffered.resolveWith(that, [result])
                    });
                else
                    store.load({filter: [valueExpr, value]}).done(function(result) {
                        deffered.resolveWith(that, result)
                    });
                return deffered.promise()
            },
            _setValueByIndex: function() {
                var index = this.option("selectedIndex"),
                    $items = this._itemElements();
                if (index < 0 || index >= $items.length) {
                    this.option("value", null);
                    return
                }
                var itemElement = this._selectedItemElement(index),
                    itemData = this._getItemData(itemElement);
                this.option("value", this._getItemValue(itemData))
            },
            _getItemValue: function(item) {
                return !!this._valueGetter ? this._valueGetter(item) : item.text
            },
            _renderSelectedIndex: function(index) {
                var $radioButtons = this._itemElements();
                $radioButtons.removeClass(RADIO_BUTTON_CHECKED_CLASS);
                if (index >= 0 && index < $radioButtons.length)
                    $radioButtons.eq(index).addClass(RADIO_BUTTON_CHECKED_CLASS)
            },
            _createItemByRenderer: function(itemRenderer, renderArgs) {
                var $itemElement = this.callBase.apply(this, arguments);
                this._renderInput($itemElement, renderArgs.item);
                return $itemElement
            },
            _createItemByTemplate: function(itemTemplate, renderArgs) {
                var $itemElement = this.callBase.apply(this, arguments);
                this._renderInput($itemElement, renderArgs.item);
                return $itemElement
            },
            _renderInput: function($element, item) {
                if (item.html)
                    return;
                var $radio = $("<div>").addClass(RADIO_BUTTON_ICON_CLASS),
                    $radioContainer = $("<div>").append($radio).addClass(RADIO_VALUE_CONTAINER_CLASS);
                $element.prepend($radioContainer)
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"value":
                        this._setIndexByValue(value);
                        break;
                    case"selectedIndex":
                        this.callBase.apply(this, arguments);
                        this._setValueByIndex();
                        break;
                    case"layout":
                        this._renderLayout();
                        this._updateContentSize();
                        break;
                    case"valueExpr":
                        this._compileValueGetter();
                        this._setValueByIndex();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.tabs.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            TABS_CLASS = "dx-tabs",
            TABS_WRAPPER_CLASS = "dx-indent-wrapper",
            TABS_ITEM_CLASS = "dx-tab",
            TABS_ITEM_SELECTOR = ".dx-tab",
            TABS_ITEM_SELECTED_CLASS = "dx-tab-selected",
            TABS_ITEM_TEXT_CLASS = "dx-tab-text",
            ICON_CLASS = "dx-icon",
            TABS_ITEM_DATA_KEY = "dxTabData",
            FEEDBACK_HIDE_TIMEOUT = 100,
            ACTIVE_STATE_CLASS = "dx-state-active";
        DX.registerComponent("dxTabs", ui.CollectionContainerWidget.inherit({
            _activeStateUnit: TABS_ITEM_SELECTOR,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({})
            },
            _init: function() {
                this.callBase();
                this._feedbackHideTimeout = FEEDBACK_HIDE_TIMEOUT
            },
            _itemClass: function() {
                return TABS_ITEM_CLASS
            },
            _itemDataKey: function() {
                return TABS_ITEM_DATA_KEY
            },
            _itemRenderDefault: function(item, index, itemElement) {
                this.callBase(item, index, itemElement);
                if (item.html)
                    return;
                var text = item.text,
                    icon = item.icon,
                    iconSrc = item.iconSrc,
                    iconElement;
                if (text)
                    itemElement.wrapInner($("<span />").addClass(TABS_ITEM_TEXT_CLASS));
                if (icon)
                    iconElement = $("<span />").addClass(ICON_CLASS + "-" + icon);
                else if (iconSrc)
                    iconElement = $("<img />").attr("src", iconSrc);
                if (iconElement)
                    iconElement.addClass(ICON_CLASS).prependTo(itemElement)
            },
            _render: function() {
                this.callBase();
                var $element = this._element();
                $element.addClass(TABS_CLASS);
                this._renderWrapper();
                $element.addClass(ACTIVE_STATE_CLASS).removeClass(ACTIVE_STATE_CLASS)
            },
            _renderWrapper: function() {
                this._element().wrapInner($("<div />").addClass(TABS_WRAPPER_CLASS))
            },
            _renderSelectedIndex: function(current, previous) {
                var $tabs = this._itemElements();
                if (previous >= 0)
                    $tabs.eq(previous).removeClass(TABS_ITEM_SELECTED_CLASS);
                if (current >= 0)
                    $tabs.eq(current).addClass(TABS_ITEM_SELECTED_CLASS)
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.navBar.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            NAVBAR_CLASS = "dx-navbar",
            NABAR_ITEM_CLASS = "dx-nav-item",
            NAVBAR_ITEM_CONTENT_CLASS = "dx-nav-item-content",
            NAVBAR_ITEM_BADGE_CLASS = "dx-navbar-item-badge";
        DX.registerComponent("dxNavBar", ui.dxTabs.inherit({
            _render: function() {
                this.callBase();
                this._element().addClass(NAVBAR_CLASS)
            },
            _postprocessRenderItem: function(args) {
                var $itemElement = args.itemElement,
                    itemData = args.itemData,
                    badge = itemData.badge;
                if (badge)
                    $("<div>").addClass(NAVBAR_ITEM_BADGE_CLASS).text(badge).appendTo($itemElement);
                $itemElement.addClass(NABAR_ITEM_CLASS);
                $itemElement.wrapInner($("<div>").addClass(NAVBAR_ITEM_CONTENT_CLASS));
                if (!itemData.icon && !itemData.iconSrc)
                    $itemElement.addClass("dx-navbar-text-item")
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.toolbar.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            fx = DX.fx,
            utils = DX.utils,
            translator = DX.translator;
        var TOOLBAR_CLASS = "dx-toolbar",
            TOOLBAR_BOTTOM_CLASS = "dx-toolbar-bottom",
            TOOLBAR_MINI_CLASS = "dx-toolbar-mini",
            TOOLBAR_ITEM_CLASS = "dx-toolbar-item",
            TOOLBAR_LABEL_CLASS = "dx-toolbar-label",
            TOOLBAR_BUTTON_CLASS = "dx-toolbar-button",
            TOOLBAR_MENU_CONTAINER_CLASS = "dx-toolbar-menu-container",
            TOOLBAR_MENU_BUTTON_CLASS = "dx-toolbar-menu-button",
            TOOLBAR_ITEMS_CONTAINER_CLASS = "dx-toolbar-items-container",
            TOOLBAR_LABEL_SELECTOR = "." + TOOLBAR_LABEL_CLASS,
            TOOLBAR_ITEM_DATA_KEY = "dxToolbarItemDataKey",
            SUBMENU_SWIPE_EASING = "easeOutCubic",
            SUBMENU_HIDE_DURATION = 200,
            SUBMENU_SHOW_DURATION = 400;
        var slideSubmenu = function($element, position, isShowAnimation) {
                var duration = isShowAnimation ? SUBMENU_SHOW_DURATION : SUBMENU_HIDE_DURATION;
                fx.animate($element, {
                    type: "slide",
                    to: {top: position},
                    easing: SUBMENU_SWIPE_EASING,
                    duration: duration
                })
            };
        DX.registerComponent("dxToolbar", ui.CollectionContainerWidget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    menuItemRender: null,
                    menuItemTemplate: "item",
                    submenuType: "dxDropDownMenu",
                    renderAs: "topToolbar"
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: [{platform: "ios"}, {platform: "ios7"}],
                            options: {submenuType: "dxActionSheet"}
                        }, {
                            device: {platform: "android"},
                            options: {submenuType: "dxDropDownMenu"}
                        }, {
                            device: {platform: "win8"},
                            options: {submenuType: "dxList"}
                        }])
            },
            _itemContainer: function() {
                return this._$toolbarItemsContainer.find([".dx-toolbar-before", ".dx-toolbar-center", ".dx-toolbar-after"].join(","))
            },
            _itemClass: function() {
                return TOOLBAR_ITEM_CLASS
            },
            _itemDataKey: function() {
                return TOOLBAR_ITEM_DATA_KEY
            },
            _itemRenderDefault: function(item, index, itemElement) {
                this.callBase(item, index, itemElement);
                var widget = item.widget;
                if (widget) {
                    var widgetElement = $("<div>").appendTo(itemElement),
                        widgetName = DX.inflector.camelize("dx-" + widget),
                        options = item.options || {};
                    widgetElement[widgetName](options)
                }
                else if (item.text)
                    itemElement.wrapInner("<div>")
            },
            _dimensionChanged: function() {
                if (this._menu)
                    this._toggleMenuVisibility(false, true);
                this._arrangeTitle()
            },
            _render: function() {
                this._renderToolbar();
                this._renderSections();
                this.callBase();
                this._renderMenu();
                this._arrangeTitle()
            },
            _renderToolbar: function() {
                this._element().addClass(TOOLBAR_CLASS).toggleClass(TOOLBAR_BOTTOM_CLASS, this.option("renderAs") === "bottomToolbar");
                this._$toolbarItemsContainer = $("<div>").appendTo(this._element());
                this._$toolbarItemsContainer.addClass(TOOLBAR_ITEMS_CONTAINER_CLASS)
            },
            _renderSections: function() {
                var $container = this._$toolbarItemsContainer,
                    that = this;
                $.each(["before", "center", "after"], function() {
                    var sectionClass = "dx-toolbar-" + this,
                        $section = $container.find("." + sectionClass);
                    if (!$section.length)
                        that["_$" + this + "Section"] = $section = $("<div>").addClass(sectionClass).appendTo($container)
                })
            },
            _arrangeTitle: function() {
                if (this._$element.is(":hidden")) {
                    this._titleUpdateIsNeeded = true;
                    return
                }
                this._titleUpdateIsNeeded = false;
                var $container = this._$toolbarItemsContainer,
                    $centerSection = this._$centerSection,
                    $label = $centerSection.children(TOOLBAR_LABEL_SELECTOR).eq(0);
                if ($label.length === 0)
                    return;
                var containerWidth = $container.width(),
                    beforeWidth = this._$beforeSection.outerWidth(),
                    afterWidth = this._$afterSection.outerWidth();
                var elemsAtCenterWidth = 10;
                $centerSection.children().not(TOOLBAR_LABEL_SELECTOR).each(function() {
                    elemsAtCenterWidth += $(this).outerWidth()
                });
                var maxLabelWidth = containerWidth - beforeWidth - afterWidth - elemsAtCenterWidth;
                var labelLongerThanMax = $label.width() > maxLabelWidth;
                $centerSection.css({
                    marginLeft: labelLongerThanMax ? beforeWidth : "",
                    marginRight: labelLongerThanMax ? afterWidth : ""
                });
                $label.css("max-width", maxLabelWidth)
            },
            _renderItem: function(index, item) {
                if (item.align)
                    utils.logger.warn("dxToolbar.items.align is deprecated. Please use dxToolbar.items.location instead.");
                var align = item.location || item.align || "center";
                if (align === "left") {
                    align = "before";
                    utils.logger.warn("dxToolbar.items.location: value 'left' is deprecated. Please use 'before' instead.")
                }
                else if (align === "right") {
                    align = "after";
                    utils.logger.warn("dxToolbar.items.location: value 'right' is deprecated. Please use 'after' instead.")
                }
                var container = this._$toolbarItemsContainer.find(".dx-toolbar-" + align);
                var itemElement = this.callBase(index, item, container);
                itemElement.addClass(TOOLBAR_BUTTON_CLASS);
                if (item.text)
                    itemElement.addClass(TOOLBAR_LABEL_CLASS).removeClass(TOOLBAR_BUTTON_CLASS);
                return itemElement
            },
            _hasVisibleMenuItems: function() {
                var menuItems = this._getMenuItems(),
                    result = false;
                var optionGetter = DevExpress.data.utils.compileGetter("visible");
                $.each(menuItems, function(index, item) {
                    var itemVisible = optionGetter(item, {functionsAsIs: true});
                    if (itemVisible !== false)
                        result = true
                });
                return result
            },
            _getToolbarItems: function() {
                return $.grep(this.option("items") || [], function(item) {
                        return item.location !== "menu"
                    })
            },
            _getMenuItems: function() {
                return $.grep(this.option("items") || [], function(item) {
                        return item.location === "menu"
                    })
            },
            _renderContentImpl: function() {
                var items = this._getToolbarItems();
                this._element().toggleClass(TOOLBAR_MINI_CLASS, items.length === 0);
                if (this._renderedItemsCount)
                    this._renderItems(items.slice(this._renderedItemsCount));
                else
                    this._renderItems(items)
            },
            _renderMenu: function() {
                var that = this,
                    itemClickAction = this._createActionByOption("itemClickAction");
                var options = {
                        itemRender: this.option("menuItemRender"),
                        itemTemplate: this.option("menuItemTemplate"),
                        itemClickAction: function(e) {
                            that._toggleMenuVisibility(false, true);
                            itemClickAction(e)
                        },
                        rtlEnabled: this.option("rtlEnabled")
                    };
                this._menuType = this.option("submenuType");
                if (this._menuType === "dxList" && this.option("renderAs") === "topToolbar")
                    this._menuType = "dxDropDownMenu";
                switch (this._menuType) {
                    case"dxActionSheet":
                        this._renderActionSheet(options);
                        break;
                    case"dxDropDownMenu":
                        this._renderDropDown(options);
                        break;
                    case"dxList":
                        this._renderList(options);
                        break
                }
            },
            _renderMenuButton: function(options) {
                var buttonOptions = $.extend({clickAction: $.proxy(this._handleMenuButtonClick, this)}, options);
                this._renderMenuButtonContainer();
                this._$button = $("<div>").appendTo(this._$menuButtonContainer).addClass(TOOLBAR_MENU_BUTTON_CLASS).dxButton(buttonOptions)
            },
            _renderMenuButtonContainer: function() {
                var $afterSection = this._$afterSection;
                this._$menuButtonContainer = $("<div>").appendTo($afterSection).addClass(TOOLBAR_BUTTON_CLASS).addClass(TOOLBAR_MENU_CONTAINER_CLASS)
            },
            _renderDropDown: function(options) {
                if (!this._hasVisibleMenuItems())
                    return;
                this._renderMenuButtonContainer();
                this._menu = $("<div>").appendTo(this._$menuButtonContainer).dxDropDownMenu(options).dxDropDownMenu("instance");
                this._renderMenuItems()
            },
            _renderActionSheet: function(options) {
                if (!this._hasVisibleMenuItems())
                    return;
                this._renderMenuButton({icon: "overflow"});
                var actionSheetOptions = $.extend({
                        target: this._$button,
                        showTitle: false
                    }, options);
                this._menu = $("<div>").appendTo(this._element()).dxActionSheet(actionSheetOptions).dxActionSheet("instance");
                this._renderMenuItems()
            },
            _renderList: function(options) {
                this._renderMenuButton({
                    activeStateEnabled: false,
                    text: "..."
                });
                var listOptions = $.extend({
                        width: "100%",
                        indicateLoading: false
                    }, options);
                this._renderListOverlay();
                this._renderContainerSwipe();
                if (this._hasVisibleMenuItems()) {
                    this._menu = $("<div>").appendTo(this._listOverlay.content()).dxList(listOptions).dxList("instance");
                    this._renderMenuItems()
                }
                this._changeListVisible(this.option("visible"))
            },
            _renderMenuItems: function() {
                this._menu.option("items", this._getMenuItems())
            },
            _getListHeight: function() {
                var listHeight = this._listOverlay.content().find(".dx-list").height(),
                    semiHiddenHeight = this._$toolbarItemsContainer.height() - this._element().height();
                return listHeight + semiHiddenHeight
            },
            _renderListOverlay: function() {
                var element = this._element();
                this._listOverlay = $("<div>").appendTo(element).dxOverlay({
                    targetContainer: false,
                    deferRendering: false,
                    shading: false,
                    height: "auto",
                    width: "100%",
                    showTitle: false,
                    closeOnOutsideClick: $.proxy(this._handleListOutsideClick, this),
                    position: null,
                    animation: null,
                    hideTopOverlayHandler: null
                }).dxOverlay("instance")
            },
            _hideTopOverlayHandler: function() {
                this._toggleMenuVisibility(false, true)
            },
            _toggleHideTopOverlayCallback: function() {
                if (this._closeCallback)
                    DX.hideTopOverlayCallback.remove(this._closeCallback);
                if (this._menuShown) {
                    this._closeCallback = $.proxy(this._hideTopOverlayHandler, this);
                    DX.hideTopOverlayCallback.add(this._closeCallback)
                }
            },
            _renderContainerSwipe: function() {
                this._$toolbarItemsContainer.appendTo(this._listOverlay.content()).dxSwipeable({
                    elastic: false,
                    startAction: $.proxy(this._handleSwipeStart, this),
                    updateAction: $.proxy(this._handleSwipeUpdate, this),
                    endAction: $.proxy(this._handleSwipeEnd, this),
                    itemSizeFunc: $.proxy(this._getListHeight, this),
                    direction: "vertical"
                })
            },
            _handleListOutsideClick: function(e) {
                if (!$(e.target).closest(this._listOverlay.content()).length)
                    this._toggleMenuVisibility(false, true)
            },
            _calculatePixelOffset: function(offset) {
                offset = (offset || 0) - 1;
                var maxOffset = this._getListHeight();
                return offset * maxOffset
            },
            _handleSwipeStart: function(e) {
                e.jQueryEvent.maxTopOffset = this._menuShown ? 0 : 1;
                e.jQueryEvent.maxBottomOffset = this._menuShown ? 1 : 0
            },
            _handleSwipeUpdate: function(e) {
                var offset = this._menuShown ? e.jQueryEvent.offset : 1 + e.jQueryEvent.offset;
                this._renderMenuPosition(offset, false)
            },
            _handleSwipeEnd: function(e) {
                var targetOffset = e.jQueryEvent.targetOffset;
                targetOffset -= this._menuShown - 1;
                this._toggleMenuVisibility(targetOffset === 0, true)
            },
            _renderMenuPosition: function(offset, animate) {
                var pos = this._calculatePixelOffset(offset),
                    element = this._listOverlay.content();
                if (animate)
                    slideSubmenu(element, pos, this._menuShown);
                else
                    translator.move(element, {top: pos})
            },
            _handleMenuButtonClick: function() {
                this._toggleMenuVisibility(!this._menuShown, true)
            },
            _toggleMenuVisibility: function(visible, animate) {
                this._menuShown = visible;
                switch (this._menuType) {
                    case"dxList":
                        this._toggleHideTopOverlayCallback();
                        this._renderMenuPosition(this._menuShown ? 0 : 1, animate);
                        break;
                    case"dxActionSheet":
                        this._menu.toggle(this._menuShown);
                        this._menuShown = false;
                        break
                }
            },
            _renderEmptyMessage: $.noop,
            _clean: function() {
                this._$toolbarItemsContainer.children().empty();
                this._element().empty()
            },
            _changeMenuOption: function(name, value) {
                if (this._menu)
                    this._menu.option(name, value)
            },
            _changeListVisible: function(value) {
                if (this._listOverlay) {
                    this._listOverlay.option("visible", value);
                    this._toggleMenuVisibility(false, false)
                }
            },
            _visibilityChanged: function(visible) {
                if (visible && this._titleUpdateIsNeeded)
                    this._arrangeTitle()
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"renderAs":
                    case"submenuType":
                        this._invalidate();
                        break;
                    case"visible":
                        this._changeListVisible(value);
                        this.callBase.apply(this, arguments);
                        break;
                    case"menuItemRender":
                        this._changeMenuOption("itemRender", value);
                        break;
                    case"menuItemTemplate":
                        this._changeMenuOption("itemTemplate", value);
                        break;
                    case"itemClickAction":
                        this._changeMenuOption(name, value);
                        this.callBase.apply(this, arguments);
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.list.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils;
        var LIST_CLASS = "dx-list",
            LIST_ITEM_CLASS = "dx-list-item",
            LIST_ITEM_SELECTOR = "." + LIST_ITEM_CLASS,
            LIST_GROUP_CLASS = "dx-list-group",
            LIST_GROUP_HEADER_CLASS = "dx-list-group-header",
            LIST_HAS_NEXT_CLASS = "dx-has-next",
            LIST_NEXT_BUTTON_CLASS = "dx-list-next-button",
            LIST_ITEM_DATA_KEY = "dxListItemData",
            LIST_FEEDBACK_SHOW_TIMEOUT = 70;
        DX.registerComponent("dxList", ui.CollectionContainerWidget.inherit({
            _activeStateUnit: LIST_ITEM_SELECTOR,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    pullRefreshEnabled: false,
                    autoPagingEnabled: true,
                    scrollingEnabled: true,
                    showScrollbar: true,
                    useNativeScrolling: true,
                    pullingDownText: Globalize.localize("dxList-pullingDownText"),
                    pulledDownText: Globalize.localize("dxList-pulledDownText"),
                    refreshingText: Globalize.localize("dxList-refreshingText"),
                    pageLoadingText: Globalize.localize("dxList-pageLoadingText"),
                    scrollAction: null,
                    pullRefreshAction: null,
                    pageLoadingAction: null,
                    showNextButton: false,
                    nextButtonText: Globalize.localize("dxList-nextButtonText"),
                    itemSwipeAction: null,
                    grouped: false,
                    groupTemplate: "group",
                    groupRender: null,
                    indicateLoading: true
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function(device) {
                                return !DX.support.nativeScrolling
                            },
                            options: {useNativeScrolling: false}
                        }, {
                            device: function(device) {
                                return !DX.support.nativeScrolling && !DX.devices.isSimulator() && DX.devices.real().platform === "generic" && device.platform === "generic"
                            },
                            options: {
                                showScrollbar: "onHover",
                                showNextButton: true,
                                autoPagingEnabled: false
                            }
                        }])
            },
            _itemClass: function() {
                return LIST_ITEM_CLASS
            },
            _itemDataKey: function() {
                return LIST_ITEM_DATA_KEY
            },
            _itemContainer: function() {
                return this._$container
            },
            _allowDinamicItemsAppend: function() {
                return true
            },
            _init: function() {
                this.callBase();
                this._$container = this._element();
                this._initScrollView();
                this._feedbackShowTimeout = LIST_FEEDBACK_SHOW_TIMEOUT
            },
            _dataSourceOptions: function() {
                return $.extend(this.callBase(), {paginate: true})
            },
            _initScrollView: function() {
                var scrollingEnabled = this.option("scrollingEnabled"),
                    pullRefreshEnabled = scrollingEnabled && this.option("pullRefreshEnabled"),
                    autoPagingEnabled = scrollingEnabled && this.option("autoPagingEnabled") && !!this._dataSource;
                var $scrollView = this._element().dxScrollView({
                        rtlEnabled: this.option("rtlEnabled"),
                        disabled: this.option("disabled") || !scrollingEnabled,
                        scrollAction: $.proxy(this._handleScroll, this),
                        pullDownAction: pullRefreshEnabled ? $.proxy(this._handlePullDown, this) : null,
                        reachBottomAction: autoPagingEnabled ? $.proxy(this._handleScrollBottom, this) : null,
                        showScrollbar: this.option("showScrollbar"),
                        useNative: this.option("useNativeScrolling"),
                        pullingDownText: this.option("pullingDownText"),
                        pulledDownText: this.option("pulledDownText"),
                        refreshingText: this.option("refreshingText"),
                        reachBottomText: this.option("pageLoadingText")
                    });
                this._scrollView = $scrollView.dxScrollView("instance");
                this._scrollView.toggleLoading(autoPagingEnabled);
                this._$container = this._scrollView.content();
                this._createScrollViewActions();
                this._afterItemsRendered()
            },
            _createScrollViewActions: function() {
                this._scrollAction = this._createActionByOption("scrollAction", {excludeValidators: ["gesture"]});
                this._pullRefreshAction = this._createActionByOption("pullRefreshAction", {excludeValidators: ["gesture"]});
                this._pageLoadingAction = this._createActionByOption("pageLoadingAction", {excludeValidators: ["gesture"]})
            },
            _handleScroll: function(e) {
                this._scrollAction(e)
            },
            _afterItemsRendered: function(tryLoadMore) {
                var isLastPage = this._isLastPage(),
                    allDataLoaded = !tryLoadMore || isLastPage,
                    autoPagingEnabled = this.option("autoPagingEnabled"),
                    stopLoading = !autoPagingEnabled || allDataLoaded,
                    scrollViewIsFull = this._scrollViewIsFull();
                if (stopLoading || scrollViewIsFull) {
                    this._scrollView.release(stopLoading);
                    this._loadIndicationSuppressed = false;
                    if (this._shouldRenderNextButton() && this._dataSource.isLoaded())
                        this._toggleNextButton(!allDataLoaded)
                }
                else
                    this._infiniteDataLoading()
            },
            _shouldRenderNextButton: function() {
                return this.option("showNextButton") && this._dataSource
            },
            _handleDataSourceLoadingChanged: function(isLoading) {
                var scrollView = this._scrollView;
                if (!scrollView || this._loadIndicationSuppressed)
                    return;
                if (isLoading && this.option("indicateLoading"))
                    scrollView.startLoading();
                else
                    scrollView.finishLoading()
            },
            _hideLoadingIfLoadIndicationOff: function() {
                if (!this.option("indicateLoading"))
                    this._handleDataSourceLoadingChanged(false)
            },
            _suppressLoadingIndication: function() {
                this._loadIndicationSuppressed = true
            },
            _isLastPage: function() {
                return !this._dataSource || this._dataSource.isLastPage()
            },
            _scrollViewIsFull: function() {
                return !this._scrollView || this._scrollView.isFull()
            },
            _handlePullDown: function(e) {
                this._pullRefreshAction(e);
                if (this._dataSource && !this._dataSource.isLoading()) {
                    this._dataSource.pageIndex(0);
                    this._dataSource.load()
                }
                else
                    this._afterItemsRendered()
            },
            _infiniteDataLoading: function() {
                var dataSource = this._dataSource;
                if (!this._scrollViewIsFull() && dataSource && !dataSource.isLoading() && !this._isLastPage())
                    this._loadNextPageTimer = setTimeout($.proxy(this._loadNextPage, this))
            },
            _handleScrollBottom: function(e) {
                this._pageLoadingAction(e);
                var dataSource = this._dataSource;
                if (dataSource && !dataSource.isLoading())
                    this._loadNextPage();
                else
                    this._afterItemsRendered()
            },
            _loadNextPage: function() {
                var dataSource = this._dataSource;
                this._expectNextPageLoading();
                dataSource.pageIndex(1 + dataSource.pageIndex());
                return dataSource.load()
            },
            _renderItems: function(items) {
                if (this.option("grouped")) {
                    $.each(items, $.proxy(this._renderGroup, this));
                    this._renderEmptyMessage()
                }
                else
                    this.callBase.apply(this, arguments);
                this._afterItemsRendered(true)
            },
            _handleDataSourceLoadError: function() {
                this.callBase.apply(this, arguments);
                if (this._initialized)
                    this._afterItemsRendered()
            },
            _render: function() {
                this._element().addClass(LIST_CLASS);
                this.callBase()
            },
            _postprocessRenderItem: function(args) {
                if (this.option("itemSwipeAction"))
                    this._attachSwipeEvent($(args.itemElement))
            },
            _attachSwipeEvent: function($itemElement) {
                var endEventName = events.addNamespace("dxswipeend", this.NAME);
                $itemElement.on(endEventName, $.proxy(this._handleItemSwipeEnd, this))
            },
            _handleItemSwipeEnd: function(e) {
                this._handleItemJQueryEvent(e, "itemSwipeAction", {direction: e.offset < 0 ? "left" : "right"}, {excludeValidators: ["gesture"]})
            },
            _handleNextButton: function() {
                var source = this._dataSource;
                if (source && !source.isLoading()) {
                    this._scrollView.toggleLoading(true);
                    this._$nextButton.detach();
                    this._suppressLoadingIndication();
                    this._loadNextPage()
                }
            },
            _groupRenderDefault: function(group) {
                return String(group.key || group)
            },
            _renderGroup: function(index, group) {
                var that = this;
                var groupElement = $("<div>").addClass(LIST_GROUP_CLASS).appendTo(that._itemContainer());
                var groupRenderer = that.option("groupRender"),
                    groupTemplateName = that.option("groupTemplate"),
                    groupTemplate = that._getTemplate(group.template || groupTemplateName, index, group),
                    groupHeaderElement,
                    renderArgs = {
                        index: index,
                        group: group,
                        container: groupElement
                    };
                if (groupRenderer)
                    groupHeaderElement = that._createGroupByRenderer(groupRenderer, renderArgs);
                else if (groupTemplate)
                    groupHeaderElement = that._createGroupByTemplate(groupTemplate, renderArgs);
                else
                    groupHeaderElement = that._createGroupByRenderer(that._groupRenderDefault, renderArgs);
                groupHeaderElement.addClass(LIST_GROUP_HEADER_CLASS);
                this._renderingGroupIndex = index;
                $.each(group.items || [], function(index, item) {
                    that._renderItem(index, item, groupElement)
                })
            },
            _createGroupByRenderer: function(groupRenderer, renderArgs) {
                var groupElement = $("<div>").appendTo(renderArgs.container);
                var rendererResult = groupRenderer(renderArgs.group, renderArgs.index, groupElement);
                if (rendererResult && groupElement[0] !== rendererResult[0])
                    groupElement.append(rendererResult);
                return groupElement
            },
            _createGroupByTemplate: function(groupTemplate, renderArgs) {
                return groupTemplate.render(renderArgs.container, renderArgs.group)
            },
            _clean: function() {
                if (this._$nextButton) {
                    this._$nextButton.remove();
                    this._$nextButton = null
                }
                this.callBase.apply(this, arguments)
            },
            _dispose: function() {
                clearTimeout(this._holdTimer);
                clearTimeout(this._loadNextPageTimer);
                this.callBase()
            },
            _toggleDisabledState: function(value) {
                this.callBase(value);
                this._scrollView.option("disabled", value || !this.option("scrollingEnabled"))
            },
            _toggleNextButton: function(value) {
                var dataSource = this._dataSource,
                    $nextButton = this._getNextButton();
                this._element().toggleClass(LIST_HAS_NEXT_CLASS, value);
                if (value && dataSource && dataSource.isLoaded())
                    $nextButton.appendTo(this._itemContainer());
                if (!value)
                    $nextButton.detach()
            },
            _getNextButton: function() {
                if (!this._$nextButton)
                    this._$nextButton = this._createNextButton();
                return this._$nextButton
            },
            _createNextButton: function() {
                var $result = $("<div>").addClass(LIST_NEXT_BUTTON_CLASS);
                $result.append($("<div>").dxButton({
                    text: this.option("nextButtonText"),
                    clickAction: $.proxy(this._handleNextButton, this)
                }));
                return $result
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"showNextButton":
                        this._toggleNextButton(value);
                        break;
                    case"dataSource":
                        this.callBase.apply(this, arguments);
                        this._initScrollView();
                        break;
                    case"pullingDownText":
                    case"pulledDownText":
                    case"refreshingText":
                    case"pageLoadingText":
                    case"useNativeScrolling":
                    case"showScrollbar":
                    case"scrollingEnabled":
                    case"pullRefreshEnabled":
                    case"autoPagingEnabled":
                        this._initScrollView();
                        break;
                    case"nextButtonText":
                    case"itemSwipeAction":
                        this._invalidate();
                        break;
                    case"scrollAction":
                    case"pullRefreshAction":
                    case"pageLoadingAction":
                        this._createScrollViewActions();
                        this._invalidate();
                        break;
                    case"grouped":
                    case"groupTemplate":
                    case"groupRender":
                        this._invalidate();
                        break;
                    case"items":
                        this._invalidate();
                        break;
                    case"width":
                    case"height":
                        this.callBase.apply(this, arguments);
                        this._scrollView.update();
                        break;
                    case"indicateLoading":
                        this._hideLoadingIfLoadIndicationOff();
                        break;
                    case"visible":
                        this.callBase.apply(this, arguments);
                        this._scrollView.update();
                        break;
                    case"rtlEnabled":
                        this._initScrollView();
                        this.callBase.apply(this, arguments);
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            update: function() {
                utils.logger.warn("'update' method is deprecated since 14.1. Use the 'updateDimensions' method instead.");
                return this.updateDimensions.apply(this, arguments)
            },
            updateDimensions: function() {
                var that = this,
                    deferred = $.Deferred();
                if (that._scrollView)
                    that._scrollView.update().done(function() {
                        deferred.resolveWith(that)
                    });
                else
                    deferred.resolveWith(that);
                return deferred.promise()
            },
            refresh: function() {
                utils.logger.warn("'refresh' method is deprecated since 14.1. Use the 'reload' method instead.");
                return this.reload.apply(this, arguments)
            },
            reload: function() {
                this._scrollView.refresh()
            },
            scrollTop: function() {
                return this._scrollView.scrollOffset().top
            },
            clientHeight: function() {
                return this._scrollView.clientHeight()
            },
            scrollHeight: function() {
                return this._scrollView.scrollHeight()
            },
            scrollBy: function(distance) {
                this._scrollView.scrollBy(distance)
            },
            scrollTo: function(location) {
                this._scrollView.scrollTo(location)
            },
            scrollToItem: function(itemElement) {
                var $itemElement = $(itemElement);
                if (!$itemElement.length)
                    return;
                var itemPosition = $itemElement.position().top,
                    itemHeight = $itemElement.outerHeight(),
                    itemBottom = itemPosition + itemHeight,
                    scrollTop = this.scrollTop(),
                    clientHeight = this.clientHeight();
                if (scrollTop <= itemPosition && itemBottom <= scrollTop + clientHeight)
                    return;
                if (scrollTop > itemPosition)
                    this.scrollTo(itemPosition);
                else
                    this.scrollTo(itemPosition + itemHeight - clientHeight)
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.list.edit.strategies.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var ListEditStrategy = DX.Class.inherit({
                ctor: function(list) {
                    this._list = list
                },
                getNormalizedIndex: function(value) {
                    if (this._isNormalisedItemIndex(value))
                        return value;
                    if (this._isItemIndex(value))
                        return this._normalizeItemIndex(value);
                    return this._getNormalizedItemIndex(value)
                },
                getIndex: function(value) {
                    if (this._isNormalisedItemIndex(value))
                        return this._denormalizeItemIndex(value);
                    if (this._isItemIndex(value))
                        return value;
                    return this._denormalizeItemIndex(this._getNormalizedItemIndex(value))
                },
                getItemElement: function(value) {
                    if (this._isNormalisedItemIndex(value))
                        return this._getItemByNormalizedIndex(value);
                    if (this._isItemIndex(value))
                        return this._getItemByNormalizedIndex(this._normalizeItemIndex(value));
                    return $(value)
                },
                deleteItemAtIndex: DX.abstract,
                updateSelectionAfterDelete: DX.abstract,
                fetchSelectedItems: DX.abstract,
                selectedItemIndecies: DX.abstract,
                itemPlacementFunc: function(movingIndex, destinationIndex) {
                    return this._itemsFromSameParent(movingIndex, destinationIndex) && movingIndex < destinationIndex ? "after" : "before"
                },
                moveItemAtIndexToIndex: DX.abstract,
                getSelectedItemsAfterReorderItem: function() {
                    return this._list.option("selectedItems")
                },
                _isNormalisedItemIndex: function(index) {
                    return $.isNumeric(index)
                },
                _isItemIndex: DX.abstract,
                _getNormalizedItemIndex: DX.abstract,
                _normalizeItemIndex: DX.abstract,
                _denormalizeItemIndex: DX.abstract,
                _getItemByNormalizedIndex: DX.abstract,
                _itemsFromSameParent: DX.abstract
            });
        ui.PlainListEditStrategy = ListEditStrategy.inherit({
            deleteItemAtIndex: function(index) {
                this._list.option("items").splice(index, 1)
            },
            updateSelectionAfterDelete: function(fromIndex) {
                var selectedItemIndices = this._list._selectedItemIndices;
                $.each(selectedItemIndices, function(i, index) {
                    if (index > fromIndex)
                        selectedItemIndices[i] -= 1
                })
            },
            fetchSelectedItems: function(indecies) {
                indecies = indecies || this._list._selectedItemIndices;
                var items = this._list.option("items"),
                    selectedItems = [];
                $.each(indecies, function(_, index) {
                    selectedItems.push(items[index])
                });
                return selectedItems
            },
            selectedItemIndecies: function() {
                var selectedIndices = [],
                    items = this._list.option("items"),
                    selected = this._list.option("selectedItems");
                $.each(selected, function(_, selectedItem) {
                    var index = $.inArray(selectedItem, items);
                    if (index !== -1)
                        selectedIndices.push(index);
                    else
                        throw new Error("Item '" + selectedItem + "' you are trying to select does not exist");
                });
                return selectedIndices
            },
            moveItemAtIndexToIndex: function(movingIndex, destinationIndex) {
                var items = this._list.option("items"),
                    movedItemData = items[movingIndex];
                items.splice(movingIndex, 1);
                items.splice(destinationIndex, 0, movedItemData)
            },
            _isItemIndex: function(index) {
                return $.isNumeric(index)
            },
            _getNormalizedItemIndex: function(itemElement) {
                return this._list._itemElements().index(itemElement)
            },
            _normalizeItemIndex: function(index) {
                return index
            },
            _denormalizeItemIndex: function(index) {
                return index
            },
            _getItemByNormalizedIndex: function(index) {
                return this._list._itemElements().eq(index)
            },
            _itemsFromSameParent: function() {
                return true
            }
        });
        var LIST_ITEM_CLASS = "dx-list-item",
            LIST_GROUP_CLASS = "dx-list-group";
        var SELECTION_SHIFT = 20,
            SELECTION_MASK = 0x8FF;
        var combineIndex = function(indices) {
                return (indices.group << SELECTION_SHIFT) + indices.item
            };
        var splitIndex = function(combinedIndex) {
                return {
                        group: combinedIndex >> SELECTION_SHIFT,
                        item: combinedIndex & SELECTION_MASK
                    }
            };
        var createGroupSelection = function(group, selectedItems) {
                var groupItems = group.items,
                    groupSelection = {
                        key: group.key,
                        items: []
                    };
                $.each(selectedItems, function(_, itemIndex) {
                    groupSelection.items.push(groupItems[itemIndex])
                });
                return groupSelection
            };
        var groupByKey = function(groups, key) {
                var length = groups.length;
                for (var i = 0; i < length; i++)
                    if (groups[i].key === key)
                        return groups[i]
            };
        ui.GroupedListEditStrategy = ListEditStrategy.inherit({
            _groupElements: function() {
                return this._list._itemContainer().find("." + LIST_GROUP_CLASS)
            },
            _groupItemElements: function($group) {
                return $group.find("." + LIST_ITEM_CLASS)
            },
            deleteItemAtIndex: function(index) {
                var indices = splitIndex(index),
                    itemGroup = this._list.option("items")[indices.group].items;
                itemGroup.splice(indices.item, 1)
            },
            updateSelectionAfterDelete: function(fromIndex) {
                var deletedIndices = splitIndex(fromIndex),
                    selectedItemIndices = this._list._selectedItemIndices;
                $.each(selectedItemIndices, function(i, index) {
                    var indices = splitIndex(index);
                    if (indices.group === deletedIndices.group && indices.item > deletedIndices.item)
                        selectedItemIndices[i] -= 1
                })
            },
            fetchSelectedItems: function(indecies) {
                indecies = indecies || this._list._selectedItemIndices;
                var items = this._list.option("items"),
                    selectedItems = [];
                indecies.sort(function(a, b) {
                    return a - b
                });
                var currentGroupIndex = 0,
                    groupSelectedIndices = [];
                $.each(indecies, function(_, combinedIndex) {
                    var index = splitIndex(combinedIndex);
                    if (index.group !== currentGroupIndex && groupSelectedIndices.length) {
                        selectedItems.push(createGroupSelection(items[currentGroupIndex], groupSelectedIndices));
                        groupSelectedIndices.length = 0
                    }
                    currentGroupIndex = index.group;
                    groupSelectedIndices.push(index.item)
                });
                if (groupSelectedIndices.length)
                    selectedItems.push(createGroupSelection(items[currentGroupIndex], groupSelectedIndices));
                return selectedItems
            },
            selectedItemIndecies: function() {
                var selectedIndices = [],
                    items = this._list.option("items"),
                    selected = this._list.option("selectedItems");
                $.each(selected, function(_, selectionInGroup) {
                    var group = groupByKey(items, selectionInGroup.key),
                        groupIndex = $.inArray(group, items);
                    if (!group)
                        throw new Error("Group with key '" + selectionInGroup.key + "' in which you are trying to select items does not exist.");
                    $.each(selectionInGroup.items, function(_, selectedGroupItem) {
                        var itemIndex = $.inArray(selectedGroupItem, group.items);
                        if (itemIndex !== -1)
                            selectedIndices.push(combineIndex({
                                group: groupIndex,
                                item: itemIndex
                            }));
                        else
                            throw new Error("Item '" + selectedGroupItem + "' you are trying to select in group '" + selectionInGroup.key + "' does not exist");
                    })
                });
                return selectedIndices
            },
            moveItemAtIndexToIndex: function(movingIndex, destinationIndex) {
                var items = this._list.option("items"),
                    movingIndices = splitIndex(movingIndex),
                    destinationIndices = splitIndex(destinationIndex),
                    movingItemGroup = items[movingIndices.group].items,
                    destinationItemGroup = items[destinationIndices.group].items,
                    movedItemData = movingItemGroup[movingIndices.item];
                movingItemGroup.splice(movingIndices.item, 1);
                destinationItemGroup.splice(destinationIndices.item, 0, movedItemData)
            },
            getSelectedItemsAfterReorderItem: function(movingIndex, destinationIndex) {
                if (this._itemsFromSameParent(movingIndex, destinationIndex) || $.inArray(movingIndex, this._list._selectedItemIndices))
                    return this.callBase();
                var items = this._list.option("items"),
                    selectedItems = this._list.option("selectedItems"),
                    movingIndices = splitIndex(movingIndex),
                    destinationIndices = splitIndex(destinationIndex),
                    movingSelectedItemGroup = selectedItems[movingIndices.group].items,
                    destinationSelectedItemGroup = selectedItems[destinationIndices.group].items,
                    movedItemData = items[movingIndices.group].items[movingIndices.item],
                    movedItemSelectedIndex = $.inArray(movedItemData, movingSelectedItemGroup);
                movingSelectedItemGroup.splice(movedItemSelectedIndex, 1);
                destinationSelectedItemGroup.push(movedItemData);
                return selectedItems
            },
            _isItemIndex: function(index) {
                return $.isNumeric(index.group) && $.isNumeric(index.item)
            },
            _getNormalizedItemIndex: function(itemElement) {
                var $item = $(itemElement),
                    $group = $item.closest("." + LIST_GROUP_CLASS);
                return combineIndex({
                        group: this._groupElements().index($group),
                        item: this._groupItemElements($group).index($item)
                    })
            },
            _normalizeItemIndex: function(index) {
                return combineIndex(index)
            },
            _denormalizeItemIndex: function(index) {
                return splitIndex(index)
            },
            _getItemByNormalizedIndex: function(index) {
                var indices = splitIndex(index),
                    $group = this._groupElements().eq(indices.group);
                return this._groupItemElements($group).eq(indices.item)
            },
            _itemsFromSameParent: function(firstIndex, secondIndex) {
                return splitIndex(firstIndex).group === splitIndex(secondIndex).group
            }
        })
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.list.edit.decorators.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            translator = DX.translator,
            fx = DX.fx,
            support = DX.support,
            utils = DX.utils;
        ui.ListEditDecoratorsRegistry = {};
        var registerDecorator = function(option, type, decoratorClass) {
                var decoratorsRegistry = ui.ListEditDecoratorsRegistry;
                var decoratorConfig = {};
                decoratorConfig[option] = decoratorsRegistry[option] ? decoratorsRegistry[option] : {};
                decoratorConfig[option][type] = decoratorClass;
                decoratorsRegistry = $.extend(decoratorsRegistry, decoratorConfig)
            };
        var LIST_ITEM_CONTENT_CLASS = "dx-list-item-content",
            LIST_ITEM_BAG_CONTAINER_CLASS = "dx-list-item-bag-container";
        var LIST_EDIT_DECORATOR = "dxListEditDecorator",
            SWIPE_START_EVENT_NAME = events.addNamespace("dxswipestart", LIST_EDIT_DECORATOR),
            SWIPE_UPDATE_EVENT_NAME = events.addNamespace("dxswipe", LIST_EDIT_DECORATOR),
            SWIPE_END_EVENT_NAME = events.addNamespace("dxswipeend", LIST_EDIT_DECORATOR),
            DRAG_START_EVENT_NAME = events.addNamespace("dxdragstart", LIST_EDIT_DECORATOR),
            DRAG_UPDATE_EVENT_NAME = events.addNamespace("dxdrag", LIST_EDIT_DECORATOR),
            DRAG_END_EVENT_NAME = events.addNamespace("dxdragend", LIST_EDIT_DECORATOR),
            POINTER_DOWN_EVENT_NAME = events.addNamespace("dxpointerdown", LIST_EDIT_DECORATOR),
            CLICK_EVENT_NAME = events.addNamespace("dxclick", LIST_EDIT_DECORATOR);
        var ListEditDecorator = DX.Class.inherit({
                ctor: function(list) {
                    this._list = list;
                    this._init()
                },
                _init: $.noop,
                _shouldHandleSwipe: false,
                _attachSwipeEvent: function(config) {
                    var swipeConfig = {itemSizeFunc: $.proxy(function() {
                                if (this._clearSwipeCache) {
                                    this._itemWidthCache = this._list._element().width();
                                    this._clearSwipeCache = false
                                }
                                return this._itemWidthCache
                            }, this)};
                    config.$itemElement.on(SWIPE_START_EVENT_NAME, swipeConfig, $.proxy(this._handleItemSwipeStart, this)).on(SWIPE_UPDATE_EVENT_NAME, $.proxy(this._handleItemSwipeUpdate, this)).on(SWIPE_END_EVENT_NAME, $.proxy(this._handleItemSwipeEnd, this))
                },
                _handleItemSwipeStart: function(e) {
                    var $itemElement = $(e.currentTarget);
                    if ($itemElement.is(".dx-state-disabled, .dx-state-disabled *")) {
                        e.cancel = true;
                        return
                    }
                    this._handleSwipeStart($itemElement, e)
                },
                _handleItemSwipeUpdate: function(e) {
                    var $itemElement = $(e.currentTarget);
                    this._handleSwipeUpdate($itemElement, e)
                },
                _handleItemSwipeEnd: function(e) {
                    var $itemElement = $(e.currentTarget);
                    this._handleSwipeEnd($itemElement, e);
                    this._clearSwipeCache = true
                },
                beforeBag: $.noop,
                afterBag: $.noop,
                modifyElement: function(config) {
                    if (this._shouldHandleSwipe) {
                        this._attachSwipeEvent(config);
                        this._clearSwipeCache = true
                    }
                },
                handleClick: $.noop,
                handleHold: $.noop,
                _handleSwipeStart: $.noop,
                _handleSwipeUpdate: $.noop,
                _handleSwipeEnd: $.noop,
                dispose: $.noop
            });
        var MENU_POSITIONING_CLASS = "dx-list-menu-positioning";
        var MenuDecorator = ListEditDecorator.inherit({
                _menuEnabled: function() {
                    return !!this._menuItems().length
                },
                _menuItems: function() {
                    return this._list.option("editConfig.menuItems")
                },
                _deleteEnabled: function() {
                    return this._list.option("editConfig.deleteEnabled")
                },
                _fireMenuAction: function($itemElement, action) {
                    this._list._handleItemEventByHandler($itemElement, action)
                }
            });
        var SWITCHABLE_DELETE_READY_CLASS = "dx-list-switchable-delete-ready",
            SWITCHABLE_DELETE_TOP_SHIELD_CLASS = "dx-list-switchable-delete-top-shield",
            SWITCHABLE_DELETE_BOTTOM_SHIELD_CLASS = "dx-list-switchable-delete-bottom-shield",
            SWITCHABLE_DELETE_ITEM_CONTENT_SHIELD_CLASS = "dx-list-switchable-delete-item-content-shield";
        var SwitchableMenuDecorator = MenuDecorator.inherit({
                _init: function() {
                    this._$topShield = $("<div />").addClass(SWITCHABLE_DELETE_TOP_SHIELD_CLASS);
                    this._$bottomShield = $("<div />").addClass(SWITCHABLE_DELETE_BOTTOM_SHIELD_CLASS);
                    this._$itemContentShield = $("<div />").addClass(SWITCHABLE_DELETE_ITEM_CONTENT_SHIELD_CLASS);
                    this._$topShield.on(POINTER_DOWN_EVENT_NAME, $.proxy(this._cancelDeleteReadyItem, this));
                    this._$bottomShield.on(POINTER_DOWN_EVENT_NAME, $.proxy(this._cancelDeleteReadyItem, this));
                    this._list._element().append(this._$topShield.toggle(false)).append(this._$bottomShield.toggle(false));
                    if (this._animatePrepareDeleteReady === DX.abstract)
                        this._animatePrepareDeleteReady = function() {
                            return $.when().promise()
                        };
                    if (this._animateForgetDeleteReady === DX.abstract)
                        this._animateForgetDeleteReady = function() {
                            return $.when().promise()
                        };
                    this._list._element().on("dxpreparetodelete", ".dx-list-item", $.proxy(function(e) {
                        this._toggleDeleteReady($(e.currentTarget))
                    }, this))
                },
                handleClick: function($itemElement) {
                    return this._cancelDeleteReadyItem()
                },
                _cancelDeleteReadyItem: function() {
                    if (!this._$readyToDeleteItem)
                        return false;
                    this._cancelDelete(this._$readyToDeleteItem);
                    return true
                },
                _cancelDelete: function($itemElement) {
                    this._toggleDeleteReady($itemElement, false)
                },
                _toggleDeleteReady: function($itemElement, readyToDelete) {
                    if (readyToDelete === undefined)
                        readyToDelete = !this._isReadyToDelete($itemElement);
                    this._toggleShields($itemElement, readyToDelete);
                    this._toggleScrolling(readyToDelete);
                    this._cacheReadyToDeleteItem($itemElement, readyToDelete);
                    this._animateToggleDelete($itemElement, readyToDelete)
                },
                _isReadyToDelete: function($itemElement) {
                    return $itemElement.hasClass(SWITCHABLE_DELETE_READY_CLASS)
                },
                _toggleShields: function($itemElement, enabled) {
                    this._$topShield.toggle(enabled);
                    this._$bottomShield.toggle(enabled);
                    if (enabled)
                        this._updateShieldsHeight($itemElement);
                    this._toggleContentShield($itemElement, enabled)
                },
                _updateShieldsHeight: function($itemElement) {
                    var $list = this._list._element(),
                        listTopOffset = $list.offset().top,
                        listHeight = $list.outerHeight(),
                        itemTopOffset = $itemElement.offset().top,
                        itemHeight = $itemElement.outerHeight(),
                        dirtyTopShieldHeight = itemTopOffset - listTopOffset,
                        dirtyBottomShieldHeight = listHeight - itemHeight - dirtyTopShieldHeight;
                    this._$topShield.height(Math.max(dirtyTopShieldHeight, 0));
                    this._$bottomShield.height(Math.max(dirtyBottomShieldHeight, 0))
                },
                _toggleContentShield: function($itemElement, enabled) {
                    if (enabled)
                        $itemElement.find("." + LIST_ITEM_CONTENT_CLASS).append(this._$itemContentShield);
                    else
                        this._$itemContentShield.detach()
                },
                _toggleScrolling: function(readyToDelete) {
                    var scrollView = this._list._element().dxScrollView("instance");
                    if (readyToDelete) {
                        this._scrollViewDisabled = scrollView.option("disabled");
                        scrollView.option("disabled", true)
                    }
                    else
                        scrollView.option("disabled", this._scrollViewDisabled)
                },
                _cacheReadyToDeleteItem: function($itemElement, cache) {
                    if (cache)
                        this._$readyToDeleteItem = $itemElement;
                    else
                        delete this._$readyToDeleteItem
                },
                _animateToggleDelete: function($itemElement, readyToDelete) {
                    if (readyToDelete) {
                        this._enablePositioning($itemElement);
                        this._prepareDeleteReady($itemElement);
                        this._animatePrepareDeleteReady($itemElement)
                    }
                    else {
                        this._forgetDeleteReady($itemElement);
                        this._animateForgetDeleteReady($itemElement).done($.proxy(this._disablePositioning, this, $itemElement))
                    }
                },
                _enablePositioning: function($itemElement) {
                    $itemElement.addClass(MENU_POSITIONING_CLASS)
                },
                _disablePositioning: function($itemElement) {
                    $itemElement.removeClass(MENU_POSITIONING_CLASS)
                },
                _prepareDeleteReady: function($itemElement) {
                    $itemElement.addClass(SWITCHABLE_DELETE_READY_CLASS)
                },
                _forgetDeleteReady: function($itemElement) {
                    $itemElement.removeClass(SWITCHABLE_DELETE_READY_CLASS)
                },
                _animatePrepareDeleteReady: DX.abstract,
                _animateForgetDeleteReady: DX.abstract,
                _deleteItem: function($itemElement) {
                    $itemElement = $itemElement || this._$readyToDeleteItem;
                    if ($itemElement.is(".dx-state-disabled, .dx-state-disabled *"))
                        return;
                    this._cancelDelete($itemElement);
                    this._list.deleteItem($itemElement)
                },
                _isRtlEnabled: function() {
                    return this._list.option("rtlEnabled")
                },
                dispose: function() {
                    if (this._$topShield)
                        this._$topShield.remove();
                    if (this._$bottomShield)
                        this._$bottomShield.remove();
                    this.callBase.apply(this, arguments)
                }
            });
        registerDecorator("menu", "_switchable", SwitchableMenuDecorator);
        var SWITCHABLE_DELETE_BUTTON_CONTAINER_CLASS = "dx-list-switchable-delete-button-container",
            SWITCHABLE_DELETE_BUTTON_WRAPPER_CLASS = "dx-list-switchable-delete-button-wrapper",
            SWITCHABLE_DELETE_BUTTON_INNER_WRAPPER_CLASS = "dx-list-switchable-delete-button-inner-wrapper",
            SWITCHABLE_DELETE_BUTTON_CLASS = "dx-list-switchable-delete-button",
            SWITCHABLE_DELETE_MENU_CLASS = "dx-list-switchable-delete-menu",
            SWITCHABLE_DELETE_BUTTON_ANIMATION_DURATION = 200;
        var SwitchableButtonDeleteDecorator = SwitchableMenuDecorator.inherit({
                _init: function() {
                    this.callBase.apply(this, arguments);
                    var $buttonContainer = $("<div >").addClass(SWITCHABLE_DELETE_BUTTON_CONTAINER_CLASS),
                        $buttonWrapper = $("<div />").addClass(SWITCHABLE_DELETE_BUTTON_WRAPPER_CLASS),
                        $buttonInnerWrapper = $("<div />").addClass(SWITCHABLE_DELETE_BUTTON_INNER_WRAPPER_CLASS),
                        $button = $("<div />").addClass(SWITCHABLE_DELETE_BUTTON_CLASS);
                    $button.dxButton({
                        text: Globalize.localize("dxListEditDecorator-delete"),
                        type: "danger",
                        clickAction: $.proxy(function(e) {
                            this._deleteItem();
                            e.jQueryEvent.stopPropagation()
                        }, this)
                    });
                    $buttonContainer.append($buttonWrapper);
                    $buttonWrapper.append($buttonInnerWrapper);
                    $buttonInnerWrapper.append($button);
                    this._$buttonContainer = $buttonContainer
                },
                _enablePositioning: function($itemElement) {
                    this.callBase.apply(this, arguments);
                    fx.stop(this._$buttonContainer, true);
                    this._$buttonContainer.appendTo($itemElement)
                },
                _disablePositioning: function() {
                    this.callBase.apply(this, arguments);
                    this._$buttonContainer.detach()
                },
                _animatePrepareDeleteReady: function() {
                    var rtl = this._isRtlEnabled(),
                        listWidth = this._list._element().width(),
                        buttonWidth = this._buttonWidth(),
                        fromValue = rtl ? listWidth : -buttonWidth,
                        toValue = rtl ? listWidth - buttonWidth : 0;
                    return fx.animate(this._$buttonContainer, {
                            type: "custom",
                            duration: SWITCHABLE_DELETE_BUTTON_ANIMATION_DURATION,
                            from: {right: fromValue},
                            to: {right: toValue}
                        })
                },
                _animateForgetDeleteReady: function() {
                    var rtl = this._isRtlEnabled(),
                        listWidth = this._list._element().width(),
                        buttonWidth = this._buttonWidth(),
                        fromValue = rtl ? listWidth - buttonWidth : 0,
                        toValue = rtl ? listWidth : -buttonWidth;
                    return fx.animate(this._$buttonContainer, {
                            type: "custom",
                            duration: SWITCHABLE_DELETE_BUTTON_ANIMATION_DURATION,
                            from: {right: fromValue},
                            to: {right: toValue}
                        })
                },
                _buttonWidth: function() {
                    if (!this._buttonContainerWidth)
                        this._buttonContainerWidth = this._$buttonContainer.outerWidth();
                    return this._buttonContainerWidth
                },
                dispose: function() {
                    if (this._$buttonContainer)
                        this._$buttonContainer.remove();
                    this.callBase.apply(this, arguments)
                }
            });
        registerDecorator("menu", "_switchableButton", SwitchableButtonDeleteDecorator);
        var TOGGLE_DELETE_SWITCH_CONTAINER_CLASS = "dx-list-toggle-delete-switch-container",
            TOGGLE_DELETE_SWITCH_CLASS = "dx-list-toggle-delete-switch";
        registerDecorator("delete", "toggle", SwitchableButtonDeleteDecorator.inherit({beforeBag: function(config) {
                var $itemElement = config.$itemElement,
                    $container = config.$container;
                var $toggle = $("<div />").dxButton({
                        icon: "toggle-delete",
                        clickAction: $.proxy(function(e) {
                            this._toggleDeleteReady($itemElement);
                            e.jQueryEvent.stopPropagation()
                        }, this)
                    }).addClass(TOGGLE_DELETE_SWITCH_CLASS);
                $container.addClass(TOGGLE_DELETE_SWITCH_CONTAINER_CLASS);
                $container.append($toggle)
            }}));
        registerDecorator("delete", "slideButton", SwitchableButtonDeleteDecorator.inherit({
            _shouldHandleSwipe: true,
            _handleSwipeEnd: function($itemElement, args) {
                if (args.targetOffset !== 0)
                    this._toggleDeleteReady($itemElement);
                return true
            }
        }));
        var SLIDE_MENU_WRAPPER_CLASS = "dx-list-slide-menu-wrapper",
            SLIDE_MENU_CONTENT_CLASS = "dx-list-slide-menu-content",
            SLIDE_MENU_BUTTONS_CONTAINER_CLASS = "dx-list-slide-menu-buttons-container",
            SLIDE_MENU_BUTTONS_CLASS = "dx-list-slide-menu-buttons",
            SLIDE_MENU_BUTTON_CLASS = "dx-list-slide-menu-button",
            SLIDE_MENU_BUTTON_MENU_CLASS = "dx-list-slide-menu-button-menu",
            SLIDE_MENU_BUTTON_DELETE_CLASS = "dx-list-slide-menu-button-delete",
            SLIDE_MENU_CLASS = "dx-list-slide-menu";
        registerDecorator("menu", "slide", SwitchableMenuDecorator.inherit({
            _shouldHandleSwipe: true,
            _init: function() {
                this.callBase.apply(this, arguments);
                this._$buttonsContainer = $("<div/>").addClass(SLIDE_MENU_BUTTONS_CONTAINER_CLASS);
                this._$buttons = $("<div/>").addClass(SLIDE_MENU_BUTTONS_CLASS).appendTo(this._$buttonsContainer);
                this._renderMenu();
                this._renderDeleteButton()
            },
            _renderMenu: function() {
                if (!this._menuEnabled())
                    return;
                var menuItems = this._menuItems();
                if (menuItems.length === 1) {
                    var menuItem = menuItems[0];
                    this._renderMenuButton(menuItem.text, $.proxy(function() {
                        this._fireAction(menuItem)
                    }, this))
                }
                else {
                    var $menu = $("<div />").addClass(SLIDE_MENU_CLASS);
                    $menu.dxActionSheet({
                        showTitle: false,
                        items: menuItems,
                        itemClickAction: $.proxy(function(args) {
                            this._fireAction(args.itemData)
                        }, this)
                    });
                    $menu.appendTo(this._list._element());
                    this._menu = $menu.dxActionSheet("instance");
                    var $menuButton = this._renderMenuButton(Globalize.localize("dxListEditDecorator-more"), $.proxy(this._menu.show, this._menu));
                    this._menu.option("target", $menuButton)
                }
            },
            _renderMenuButton: function(text, action) {
                var $menuButton = $("<div/>").addClass(SLIDE_MENU_BUTTON_CLASS).addClass(SLIDE_MENU_BUTTON_MENU_CLASS).text(text);
                this._$buttons.append($menuButton);
                $menuButton.on(CLICK_EVENT_NAME, action);
                return $menuButton
            },
            _renderDeleteButton: function() {
                if (!this._deleteEnabled())
                    return;
                var $deleteButton = $("<div/>").addClass(SLIDE_MENU_BUTTON_CLASS).addClass(SLIDE_MENU_BUTTON_DELETE_CLASS).text(Globalize.localize("dxListEditDecorator-delete"));
                $deleteButton.on(CLICK_EVENT_NAME, $.proxy(function() {
                    this._deleteItem()
                }, this));
                this._$buttons.append($deleteButton)
            },
            _fireAction: function(menuItem) {
                this._fireMenuAction($(this._cachedNode), menuItem.action);
                this._cancelDeleteReadyItem()
            },
            modifyElement: function(config) {
                this.callBase.apply(this, arguments);
                var $itemElement = config.$itemElement;
                $itemElement.addClass(SLIDE_MENU_WRAPPER_CLASS).removeClass(LIST_ITEM_BAG_CONTAINER_CLASS);
                var $slideMenuContent = $("<div/>").addClass(SLIDE_MENU_CONTENT_CLASS).addClass(LIST_ITEM_BAG_CONTAINER_CLASS);
                $itemElement.wrapInner($slideMenuContent)
            },
            handleClick: function(_, e) {
                if ($(e.target).closest("." + SLIDE_MENU_CONTENT_CLASS).length)
                    return this.callBase.apply(this, arguments);
                return true
            },
            _handleSwipeStart: function($itemElement) {
                this._enablePositioning($itemElement);
                this._cacheItemData($itemElement)
            },
            _handleSwipeUpdate: function($itemElement, args) {
                var rtl = this._isRtlEnabled(),
                    signCorrection = rtl ? -1 : 1,
                    offset = this._cachedItemWidth * args.offset,
                    startOffset = this._isReadyToDelete($itemElement) ? -this._cachedButtonWidth * signCorrection : 0,
                    correctedOffset = (offset + startOffset) * signCorrection,
                    contentPosition = correctedOffset < 0 ? offset + startOffset : 0,
                    buttonPosition = correctedOffset < 0 ? correctedOffset : 0;
                translator.move(this._$cachedContent, {left: contentPosition});
                this._$buttonsContainer.css(rtl ? "right" : "left", Math.max(this._cachedItemWidth + buttonPosition, this._minButtonContainerLeftOffset()));
                return true
            },
            _cacheItemData: function($itemElement) {
                if ($itemElement[0] === this._cachedNode)
                    return;
                this._$cachedContent = $itemElement.find("." + SLIDE_MENU_CONTENT_CLASS);
                this._cachedItemWidth = $itemElement.outerWidth();
                this._cachedButtonWidth = this._cachedButtonWidth || $itemElement.find("." + SLIDE_MENU_BUTTONS_CLASS).outerWidth();
                if (this._$cachedContent.length)
                    this._cachedNode = $itemElement[0]
            },
            _minButtonContainerLeftOffset: function() {
                return this._cachedItemWidth - this._cachedButtonWidth
            },
            _handleSwipeEnd: function($itemElement, args) {
                this._cacheItemData($itemElement);
                var signCorrection = this._isRtlEnabled() ? 1 : -1,
                    offset = this._cachedItemWidth * args.offset,
                    endedAtReadyToDelete = !this._isReadyToDelete($itemElement) && offset * signCorrection > this._cachedButtonWidth * .2,
                    readyToDelete = args.targetOffset === signCorrection || endedAtReadyToDelete;
                this._toggleDeleteReady($itemElement, readyToDelete);
                return true
            },
            _enablePositioning: function($itemElement) {
                this.callBase.apply(this, arguments);
                this._$buttonsContainer.appendTo($itemElement)
            },
            _disablePositioning: function($itemElement) {
                this.callBase.apply(this, arguments);
                this._$buttonsContainer.detach()
            },
            _animatePrepareDeleteReady: function() {
                var rtl = this._isRtlEnabled(),
                    directionCorrection = rtl ? 1 : -1;
                this._$buttonsContainer.css(rtl ? "left" : "right", "0");
                var contentAnimation = fx.animate(this._$cachedContent, {
                        to: {left: this._cachedButtonWidth * directionCorrection},
                        type: "slide",
                        duration: 200
                    });
                var direction = rtl ? "right" : "left",
                    buttonToAnimation = {};
                buttonToAnimation[direction] = this._minButtonContainerLeftOffset();
                var buttonAnimation = fx.animate(this._$buttonsContainer, {
                        to: buttonToAnimation,
                        duration: 200
                    });
                return $.when(contentAnimation, buttonAnimation).promise()
            },
            _animateForgetDeleteReady: function($itemElement) {
                this._cacheItemData($itemElement);
                var rtl = this._isRtlEnabled();
                this._$buttonsContainer.css(rtl ? "left" : "right", "0");
                var contentAnimation = fx.animate(this._$cachedContent, {
                        to: {left: 0},
                        type: "slide",
                        duration: 200
                    });
                var direction = rtl ? "right" : "left",
                    buttonToAnimation = {};
                buttonToAnimation[direction] = this._cachedItemWidth;
                var buttonAnimation = fx.animate(this._$buttonsContainer, {
                        to: buttonToAnimation,
                        duration: 200,
                        complete: $.proxy(function() {
                            this._$buttonsContainer.css(direction, "100%")
                        }, this)
                    });
                return $.when(contentAnimation, buttonAnimation).promise()
            },
            dispose: function() {
                if (this._menu)
                    this._menu._element().remove();
                if (this._$buttonsContainer)
                    this._$buttonsContainer.remove();
                this.callBase.apply(this, arguments)
            }
        }));
        registerDecorator("delete", "swipe", ListEditDecorator.inherit({
            _shouldHandleSwipe: true,
            _renderItemPosition: function($itemElement, offset, animate) {
                var deferred = $.Deferred(),
                    itemOffset = offset * this._itemElementWidth;
                if (animate)
                    fx.animate($itemElement, {
                        to: {left: itemOffset},
                        type: "slide",
                        complete: function() {
                            deferred.resolve($itemElement, offset)
                        }
                    });
                else {
                    translator.move($itemElement, {left: itemOffset});
                    deferred.resolve()
                }
                return deferred.promise()
            },
            _handleSwipeStart: function($itemElement) {
                this._itemElementWidth = $itemElement.width();
                return true
            },
            _handleSwipeUpdate: function($itemElement, args) {
                this._renderItemPosition($itemElement, args.offset);
                return true
            },
            _handleSwipeEnd: function($itemElement, args) {
                var offset = args.targetOffset;
                this._renderItemPosition($itemElement, offset, true).done($.proxy(function($itemElement, offset) {
                    if (Math.abs(offset))
                        this._list.deleteItem($itemElement)
                }, this));
                return true
            }
        }));
        var HOLDDELETE_MENU = "dx-list-holddelete-menu",
            HOLDDELETE_MENUCONTENT = "dx-list-holddelete-menucontent";
        registerDecorator("menu", "hold", MenuDecorator.inherit({
            _init: function() {
                var $menu = $("<div/>").addClass(HOLDDELETE_MENU);
                this._list._element().append($menu);
                this._menu = this._renderOverlay($menu)
            },
            _renderOverlay: function($element) {
                return $element.dxOverlay({
                        shading: false,
                        deferRendering: true,
                        closeOnTargetScroll: true,
                        closeOnOutsideClick: function(e) {
                            return !$(e.target).closest("." + HOLDDELETE_MENU).length
                        },
                        animation: {
                            show: {
                                type: "slide",
                                duration: 300,
                                from: {
                                    height: 0,
                                    opacity: 1
                                },
                                to: {
                                    height: $.proxy(function() {
                                        return this._$menuList.outerHeight()
                                    }, this),
                                    opacity: 1
                                }
                            },
                            hide: {
                                type: "slide",
                                duration: 0,
                                from: {opacity: 1},
                                to: {opacity: 0}
                            }
                        },
                        height: $.proxy(function() {
                            return this._$menuList ? this._$menuList.outerHeight() : 0
                        }, this),
                        width: $.proxy(function() {
                            return this._list._element().outerWidth()
                        }, this),
                        contentReadyAction: $.proxy(this._renderMenuContent, this)
                    }).dxOverlay("instance")
            },
            _renderMenuContent: function(e) {
                var $overlayContent = e.component.content();
                var items = this._menuItems().slice();
                if (this._deleteEnabled())
                    items.push({
                        text: Globalize.localize("dxListEditDecorator-delete"),
                        action: $.proxy(this._deleteItem, this)
                    });
                this._$menuList = $("<div>").dxList({
                    items: items,
                    itemClickAction: $.proxy(this._handleMenuItemClick, this),
                    height: "auto"
                });
                $overlayContent.addClass(HOLDDELETE_MENUCONTENT);
                $overlayContent.append(this._$menuList)
            },
            _handleMenuItemClick: function(args) {
                this._menu.hide();
                this._fireMenuAction(this._$itemWithMenu, args.itemData.action)
            },
            _deleteItem: function() {
                this._list.deleteItem(this._$itemWithMenu)
            },
            handleHold: function($itemElement) {
                this._$itemWithMenu = $itemElement;
                this._menu.option({position: {
                        my: "top",
                        at: "bottom",
                        of: $itemElement,
                        collision: "flip"
                    }});
                this._menu.show();
                return true
            },
            dispose: function() {
                if (this._menu)
                    this._menu._element().remove();
                this.callBase.apply(this, arguments)
            }
        }));
        var LIST_ITEM_SELECTED_CLASS = "dx-list-item-selected",
            SELECT_DECORATOR_ENABLED_CLASS = "dx-list-select-decorator-enabled",
            SELECT_CHECKBOX_CONTAINER_CLASS = "dx-list-select-checkbox-container",
            SELECT_CHECKBOX_CLASS = "dx-list-select-checkbox",
            SELECT_RADIO_BUTTON_CONTAINER_CLASS = "dx-list-select-radio-button-container",
            SELECT_RADIO_BUTTON_CLASS = "dx-list-select-radio-button";
        registerDecorator("selection", "control", ListEditDecorator.inherit({
            _init: function() {
                this.callBase.apply(this, arguments);
                var selectionMode = this._list.option("selectionMode");
                this._singleStrategy = selectionMode === "single";
                this._containerClass = this._singleStrategy ? SELECT_RADIO_BUTTON_CONTAINER_CLASS : SELECT_CHECKBOX_CONTAINER_CLASS;
                this._controlClass = this._singleStrategy ? SELECT_RADIO_BUTTON_CLASS : SELECT_CHECKBOX_CLASS;
                this._controlWidget = this._singleStrategy ? "dxRadioButton" : "dxCheckBox";
                this._list._element().addClass(SELECT_DECORATOR_ENABLED_CLASS)
            },
            beforeBag: function(config) {
                var $itemElement = config.$itemElement,
                    $container = config.$container;
                var $control = $("<div />").addClass(this._controlClass);
                $control[this._controlWidget]({
                    value: this._isSelected($itemElement),
                    valueChangeAction: $.proxy(function(e) {
                        this._processCheckedState($itemElement, e.value);
                        if (e.jQueryEvent)
                            e.jQueryEvent.stopPropagation()
                    }, this)
                });
                $container.addClass(this._containerClass);
                $container.append($control)
            },
            modifyElement: function(config) {
                this.callBase.apply(this, arguments);
                var $itemElement = config.$itemElement,
                    control = $itemElement.find("." + this._controlClass)[this._controlWidget]("instance");
                $itemElement.on("stateChanged", $.proxy(function() {
                    control.option("value", this._isSelected($itemElement))
                }, this))
            },
            _isSelected: function($itemElement) {
                return $itemElement.hasClass(LIST_ITEM_SELECTED_CLASS)
            },
            _processCheckedState: function($itemElement, checked) {
                if (checked)
                    this._list.selectItem($itemElement);
                else
                    this._list.unselectItem($itemElement)
            },
            dispose: function() {
                this._list._element().removeClass(SELECT_DECORATOR_ENABLED_CLASS);
                this.callBase.apply(this, arguments)
            }
        }));
        registerDecorator("selection", "item", ui.ListEditDecoratorsRegistry.selection.control.inherit({handleClick: function($itemElement) {
                var newState = !this._isSelected($itemElement) || this._singleStrategy;
                this._processCheckedState($itemElement, newState);
                return true
            }}));
        var REORDER_HANDLE_CONTAINER_CLASS = "dx-list-reorder-handle-container",
            REORDER_HANDLE_CLASS = "dx-list-reorder-handle",
            REOREDERING_ITEM_CLASS = "dx-list-item-reordering",
            REOREDERING_ITEM_GHOST_CLASS = "dx-list-item-ghost-reordering",
            LIST_REORDER_COMPATIBILITY_MODE_CLASS = "dx-list-reorder-compatibility-mode";
        var fromRange = function(value, minValue, maxValue) {
                return Math.min(Math.max(value, minValue), maxValue)
            };
        var ReorderScrollAnimator = DX.Animator.inherit({
                ctor: function(strategy) {
                    this.callBase();
                    this._strategy = strategy
                },
                _isFinished: function() {
                    return this._strategy.scrollFinished()
                },
                _step: function() {
                    this._strategy.scrollByStep()
                }
            });
        registerDecorator("reorder", "default", ListEditDecorator.inherit({
            _init: function() {
                this._groupedEnabled = this._list.option("grouped");
                this._initAnimator()
            },
            _initAnimator: function() {
                this._scrollAnimator = new ReorderScrollAnimator(this)
            },
            _startAnimator: function() {
                if (!this._scrollAnimator.inProgress())
                    this._scrollAnimator.start()
            },
            _stopAnimator: function() {
                this._scrollAnimator.stop()
            },
            afterBag: function(config) {
                var $itemElement = config.$itemElement,
                    $container = config.$container;
                var $handle = $("<div>").addClass(REORDER_HANDLE_CLASS);
                $handle.on(DRAG_START_EVENT_NAME, {direction: "vertical"}, $.proxy(this._handleDragStart, this, $itemElement));
                $handle.on(DRAG_UPDATE_EVENT_NAME, $.proxy(this._handleDrag, this, $itemElement));
                $handle.on(DRAG_END_EVENT_NAME, $.proxy(this._handleDragEnd, this, $itemElement));
                $container.addClass(REORDER_HANDLE_CONTAINER_CLASS);
                $container.append($handle)
            },
            _handleDragStart: function($itemElement, e) {
                this._stopPreviousAnimation();
                e.targetElements = [];
                this._cacheItemsPositions();
                this._startPointerOffset = e.pageY - $itemElement.offset().top;
                this._elementHeight = $itemElement.outerHeight();
                var itemIndex = this._list.getFlatIndexByItemElement($itemElement);
                this._startIndex = itemIndex;
                this._lastIndex = itemIndex;
                this._cacheScrollData();
                this._createGhost($itemElement);
                $itemElement.addClass(REOREDERING_ITEM_CLASS);
                this._toggleCompatibilityMode(true)
            },
            _stopPreviousAnimation: function() {
                fx.stop(this._$ghostItem, true)
            },
            _toggleCompatibilityMode: function(enabled) {
                this._list._element().toggleClass(LIST_REORDER_COMPATIBILITY_MODE_CLASS, !support.transform3d && enabled)
            },
            _cacheItemsPositions: function() {
                this._itemPositions = [];
                $.each(this._list.itemElements(), $.proxy(function(index, item) {
                    this._itemPositions.push($(item).position().top)
                }, this))
            },
            _getDraggingElementPosition: function() {
                return this._itemPositions[this._startIndex]
            },
            _getLastElementPosition: function() {
                return this._itemPositions[this._lastIndex]
            },
            _cacheScrollData: function() {
                this._list.updateDimensions();
                this._startScrollTop = this._list.scrollTop();
                this._scrollOffset = 0;
                this._scrollHeight = this._list.scrollHeight();
                this._clientHeight = this._list.clientHeight()
            },
            _scrollTop: function() {
                return this._startScrollTop + this._scrollOffset
            },
            _createGhost: function($itemElement) {
                this._$ghostItem = $itemElement.clone();
                this._$ghostItem.addClass(REOREDERING_ITEM_GHOST_CLASS).appendTo(this._list.itemsContainer());
                this._startGhostPosition = this._getDraggingElementPosition() - this._$ghostItem.position().top;
                translator.move(this._$ghostItem, {top: this._startGhostPosition})
            },
            _handleDrag: function($itemElement, e) {
                this._topOffset = e.offset.y;
                this._updateItemPositions();
                var pointerPosition = this._getPonterPosition();
                this._toggleScroll(pointerPosition)
            },
            _getPonterPosition: function() {
                return this._getDraggingElementPosition() + this._startPointerOffset + this._scrollOffset + this._topOffset
            },
            _toggleScroll: function(pointerPosition) {
                if (this._scrollHeight <= this._clientHeight)
                    return;
                var minOffset = this._elementHeight * .7,
                    topOffset = this._clientHeight - (pointerPosition - this._scrollTop()),
                    topOffsetRatio = topOffset / minOffset,
                    bottomOffset = pointerPosition - this._scrollTop(),
                    bottomOffsetRatio = bottomOffset / minOffset;
                if (topOffsetRatio < 1) {
                    this._stepSize = this._adjustRationIntoRange(topOffsetRatio);
                    this._startAnimator()
                }
                else if (bottomOffsetRatio < 1) {
                    this._stepSize = -this._adjustRationIntoRange(bottomOffsetRatio);
                    this._startAnimator()
                }
                else
                    this._stopAnimator()
            },
            _adjustRationIntoRange: function(ratio) {
                return fromRange(Math.round(Math.abs(ratio - 1) * 7), 1, 7)
            },
            _updateItemPositions: function() {
                this._updateGhostPosition();
                this._updateOthersPositions()
            },
            _updateGhostPosition: function() {
                translator.move(this._$ghostItem, {top: this._startGhostPosition + this._scrollOffset + this._topOffset})
            },
            _updateOthersPositions: function() {
                var currentIndex = this._findItemIndexByPosition(this._getPonterPosition());
                if (this._lastIndex === currentIndex || this._groupedEnabled && !this._sameParent(currentIndex))
                    return;
                var currentIndexOffset = currentIndex - this._startIndex,
                    currentDirection = utils.sign(currentIndexOffset),
                    minIndex = Math.min(currentIndex, this._lastIndex),
                    maxIndex = Math.max(currentIndex, this._lastIndex);
                for (var itemIndex = minIndex; itemIndex <= maxIndex; itemIndex++) {
                    if (itemIndex === this._startIndex)
                        continue;
                    var $item = this._list.getItemElementByFlatIndex(itemIndex),
                        itemIndexOffset = itemIndex - this._startIndex,
                        itemDirection = utils.sign(itemIndexOffset),
                        offsetsDifference = Math.abs(itemIndexOffset) <= Math.abs(currentIndexOffset),
                        sameDirections = currentDirection === itemDirection,
                        setupPosition = offsetsDifference && sameDirections,
                        resetPosition = !offsetsDifference || !sameDirections;
                    fx.stop($item);
                    if (setupPosition)
                        fx.animate($item, {
                            type: "slide",
                            to: {top: this._elementHeight * -currentDirection},
                            duration: 300
                        });
                    if (resetPosition)
                        fx.animate($item, {
                            type: "slide",
                            to: {top: 0},
                            duration: 300
                        })
                }
                this._lastIndex = currentIndex
            },
            _sameParent: function(index) {
                var $dragging = this._list.getItemElementByFlatIndex(this._startIndex),
                    $over = this._list.getItemElementByFlatIndex(index);
                return $over.parent().get(0) === $dragging.parent().get(0)
            },
            scrollByStep: function() {
                this._scrollOffset += this._stepSize;
                this._list.scrollBy(this._stepSize);
                this._updateItemPositions()
            },
            scrollFinished: function() {
                var scrollTop = this._scrollTop(),
                    rejectScrollTop = scrollTop <= 0 && this._stepSize < 0,
                    rejectScrollBottom = scrollTop >= this._scrollHeight - this._clientHeight && this._stepSize > 0;
                return rejectScrollTop || rejectScrollBottom
            },
            _handleDragEnd: function($itemElement) {
                this._scrollAnimator.stop();
                fx.animate(this._$ghostItem, {
                    type: "slide",
                    to: {top: this._startGhostPosition + this._getLastElementPosition() - this._getDraggingElementPosition()},
                    duration: 300
                }).done($.proxy(function() {
                    $itemElement.removeClass(REOREDERING_ITEM_CLASS);
                    this._resetPositions();
                    this._list.reorderItem($itemElement, this._list.getItemElementByFlatIndex(this._lastIndex));
                    this._deleteGhost();
                    this._toggleCompatibilityMode(false)
                }, this))
            },
            _deleteGhost: function() {
                this._$ghostItem.remove()
            },
            _resetPositions: function() {
                var minIndex = Math.min(this._startIndex, this._lastIndex),
                    maxIndex = Math.max(this._startIndex, this._lastIndex);
                for (var itemIndex = minIndex; itemIndex <= maxIndex; itemIndex++) {
                    var $item = this._list.getItemElementByFlatIndex(itemIndex);
                    translator.resetPosition($item)
                }
            },
            _findItemIndexByPosition: function(position) {
                var minIndex = 0;
                var maxIndex = this._itemPositions.length - 1;
                var currentIndex;
                var currentPosition;
                while (minIndex <= maxIndex) {
                    currentIndex = (minIndex + maxIndex) / 2 | 0;
                    currentPosition = this._itemPositions[currentIndex];
                    if (currentPosition < position)
                        minIndex = currentIndex + 1;
                    else if (currentPosition > position)
                        maxIndex = currentIndex - 1;
                    else
                        return currentIndex
                }
                return fromRange(minIndex, 0, Math.max(maxIndex, 0))
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.list.edit.provider.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils;
        var editOptionsRegistry = [];
        var registerOption = function(enabledFunc, decoratorTypeFunc, decoratorSubTypeFunc) {
                editOptionsRegistry.push({
                    enabled: enabledFunc,
                    decoratorType: decoratorTypeFunc,
                    decoratorSubType: decoratorSubTypeFunc
                })
            };
        registerOption(function(config) {
            return config.menuItems.length
        }, function() {
            return "menu"
        }, function(config) {
            return config.menuType
        });
        registerOption(function(config) {
            return !config.menuItems.length && config.deleteEnabled
        }, function(config, defaultConfig) {
            var deleteType = config.deleteMode !== defaultConfig.deleteMode ? config.deleteMode : config.deleteType;
            return deleteType === "toggle" || deleteType === "slideButton" || deleteType === "swipe" ? "delete" : "menu"
        }, function(config, defaultConfig) {
            var deleteType;
            if (config.deleteMode !== defaultConfig.deleteMode) {
                utils.logger.warn("'deleteMode' option is deprecated since 14.1. Use the 'deleteType' option instead.");
                deleteType = config.deleteMode
            }
            else
                deleteType = config.deleteType;
            if (deleteType === "slideItem")
                deleteType = "slide";
            return deleteType
        });
        registerOption(function(config) {
            return config.selectionEnabled
        }, function() {
            return "selection"
        }, function(config, defaultConfig) {
            var selectionType;
            if (config.selectionMode !== defaultConfig.selectionMode) {
                utils.logger.warn("'selectionMode' option is deprecated since 14.1. Use the 'selectionType' option instead.");
                selectionType = config.selectionMode
            }
            else
                selectionType = config.selectionType;
            return selectionType
        });
        registerOption(function(config) {
            return config.reorderEnabled
        }, function() {
            return "reorder"
        }, function() {
            return "default"
        });
        var LIST_ITEM_BAG_CONTAINER_CLASS = "dx-list-item-bag-container",
            LIST_ITEM_CONTENT_CLASS = "dx-list-item-content",
            LIST_ITEM_BEFORE_BAG_CLASS = "dx-list-item-before-bag",
            LIST_ITEM_AFTER_BAG_CLASS = "dx-list-item-after-bag",
            DECORATOR_BEFORE_BAG_CREATE_METHOD = "beforeBag",
            DECORATOR_AFTER_BAG_CREATE_METHOD = "afterBag",
            DECORATOR_MODIFY_ELEMENT_METHOD = "modifyElement";
        ui.ListEditProvider = DX.Class.inherit({
            ctor: function(list, config, defaultConfig) {
                this._list = list;
                this._config = config;
                this._defaultConfig = defaultConfig;
                if (this.isModifyingByDecorators())
                    this._fetchRequiredDecorators()
            },
            dispose: function() {
                if (this._decorators && this._decorators.length)
                    $.each(this._decorators, function(_, decorator) {
                        decorator.dispose()
                    })
            },
            isModifyingByDecorators: function(itemData) {
                return !(this.isRenderingByRenderer() || this.isRenderingByTemplate(itemData))
            },
            isRenderingByRenderer: function() {
                return !!this.getItemRenderer()
            },
            getItemRenderer: function() {
                return this._config.itemRender
            },
            isRenderingByTemplate: function(itemData) {
                return !!this.getItemTemplateName(itemData)
            },
            getItemTemplateName: function(itemData) {
                return itemData && itemData.editTemplate || this._config.itemTemplate
            },
            _fetchRequiredDecorators: function() {
                this._decorators = [];
                var config = this._config,
                    defaultConfig = this._defaultConfig;
                $.each(editOptionsRegistry, $.proxy(function(_, option) {
                    var optionEnabled = option.enabled(config, defaultConfig);
                    if (optionEnabled) {
                        var decoratorType = option.decoratorType(config, defaultConfig),
                            decoratorSubType = option.decoratorSubType(config, defaultConfig),
                            decorator = this._createDecorator(decoratorType, decoratorSubType);
                        this._decorators.push(decorator)
                    }
                }, this))
            },
            _createDecorator: function(type, subType) {
                var decoratorClass = this._findDecorator(type, subType);
                return new decoratorClass(this._list)
            },
            _findDecorator: function(type, subType) {
                var foundDecorator = ui.ListEditDecoratorsRegistry[type][subType];
                if (!foundDecorator)
                    throw new Error("Decorator with editing type: \"" + type + "\" and sub type: \"" + subType + "\" not found");
                return foundDecorator
            },
            modifyItemElement: function(args) {
                var $itemElement = $(args.itemElement);
                $itemElement.addClass(LIST_ITEM_BAG_CONTAINER_CLASS);
                this._wrapContent($itemElement);
                var config = {$itemElement: $itemElement};
                this._prependBeforeBags($itemElement, config);
                this._appendAfterBags($itemElement, config);
                this._applyDecorators(DECORATOR_MODIFY_ELEMENT_METHOD, config)
            },
            _wrapContent: function($itemElement) {
                var $contentContainer = $("<div />").addClass(LIST_ITEM_CONTENT_CLASS);
                $itemElement.wrapInner($contentContainer)
            },
            _prependBeforeBags: function($itemElement, config) {
                var $beforeBags = this._collectDecoratorsMarkup(DECORATOR_BEFORE_BAG_CREATE_METHOD, config, LIST_ITEM_BEFORE_BAG_CLASS);
                $itemElement.prepend($beforeBags)
            },
            _appendAfterBags: function($itemElement, config) {
                var $afterBags = this._collectDecoratorsMarkup(DECORATOR_AFTER_BAG_CREATE_METHOD, config, LIST_ITEM_AFTER_BAG_CLASS);
                $itemElement.append($afterBags)
            },
            _collectDecoratorsMarkup: function(method, config, containerClass) {
                var $collector = $("<div />");
                $.each(this._decorators, function() {
                    var $container = $("<div />").addClass(containerClass);
                    this[method]($.extend({$container: $container}, config));
                    if ($container.children().length)
                        $collector.append($container)
                });
                return $collector.children()
            },
            _applyDecorators: function(method, config) {
                $.each(this._decorators, function() {
                    this[method](config)
                })
            },
            _handlerExists: function(name) {
                if (!this._decorators)
                    return false;
                var decorators = this._decorators,
                    length = decorators.length;
                for (var i = 0; i < length; i++)
                    if (decorators[i][name] !== $.noop)
                        return true;
                return false
            },
            _handleEvent: function(name, $itemElement, e) {
                if (!this._decorators)
                    return false;
                var response = false,
                    decorators = this._decorators,
                    length = decorators.length;
                for (var i = 0; i < length; i++) {
                    response = decorators[i][name]($itemElement, e);
                    if (response)
                        break
                }
                return response
            },
            handleClick: function($itemElement, e) {
                return this._handleEvent("handleClick", $itemElement, e)
            },
            holdHandlerExists: function() {
                return this._handlerExists("handleHold")
            },
            handleHold: function($itemElement, e) {
                return this._handleEvent("handleHold", $itemElement, e)
            }
        })
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.list.edit.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            removeDublicates = utils.removeDublicates;
        var LIST_EDITING_CLASS = "dx-list-editing",
            LIST_ITEM_SELECTED_CLASS = "dx-list-item-selected",
            LIST_ITEM_RESPONSE_WAIT_CLASS = "dx-list-item-response-wait";
        DX.registerComponent("dxList", ui.dxList.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    editEnabled: false,
                    editConfig: {
                        itemTemplate: null,
                        itemRender: null,
                        menuType: "hold",
                        menuItems: [],
                        deleteEnabled: false,
                        deleteMode: "toggle",
                        deleteType: "toggle",
                        selectionEnabled: false,
                        selectionMode: "item",
                        selectionType: "item",
                        reorderEnabled: false
                    },
                    itemDeleteAction: null,
                    selectionMode: 'multi',
                    selectedItems: [],
                    itemSelectAction: null,
                    itemUnselectAction: null,
                    itemReorderAction: null
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: {platform: "ios"},
                            options: {editConfig: {
                                    deleteType: "slideButton",
                                    deleteMode: "slideButton"
                                }}
                        }, {
                            device: {platform: "ios7"},
                            options: {editConfig: {
                                    menuType: "slide",
                                    deleteType: "slideItem",
                                    deleteMode: "slideItem"
                                }}
                        }, {
                            device: {platform: "android"},
                            options: {editConfig: {
                                    deleteType: "swipe",
                                    deleteMode: "swipe"
                                }}
                        }, {
                            device: {platform: "win8"},
                            options: {editConfig: {
                                    deleteType: "hold",
                                    deleteMode: "hold"
                                }}
                        }, {
                            device: {platform: "generic"},
                            options: {editConfig: {
                                    deleteType: "slideItem",
                                    deleteMode: "slideItem"
                                }}
                        }])
            },
            _init: function() {
                this.callBase();
                this._initEditProvider();
                this._initEditStrategy(this.option("grouped"));
                this._initSelectedItems()
            },
            _initEditProvider: function() {
                var defaultConfig = this.initialOption("editConfig");
                this._editProvider = new ui.ListEditProvider(this, this.option("editConfig"), defaultConfig)
            },
            _disposeEditProvider: function() {
                if (this._editProvider)
                    this._editProvider.dispose()
            },
            _refreshEditProvider: function() {
                this._disposeEditProvider();
                this._initEditProvider()
            },
            _initEditStrategy: function(grouped) {
                var strategy = grouped ? ui.GroupedListEditStrategy : ui.PlainListEditStrategy;
                this._editStrategy = new strategy(this)
            },
            _initSelectedItems: function() {
                this._selectedItemIndices = this._editStrategy.selectedItemIndecies(this.option("selectedItems"))
            },
            _clearSelectedItems: function() {
                this._selectedItemIndices = [];
                this.option("selectedItems", [])
            },
            _render: function() {
                this._renderEditing();
                this.callBase();
                this._normalizeSelectedItems()
            },
            _renderEditing: function() {
                this._element().toggleClass(LIST_EDITING_CLASS, this.option("editEnabled"))
            },
            _handleItemClick: function(e) {
                var $itemElement = $(e.currentTarget);
                if ($itemElement.is(".dx-state-disabled, .dx-state-disabled *"))
                    return;
                var handledByEditProvider = this.option("editEnabled") && this._editProvider.handleClick($itemElement, e);
                if (handledByEditProvider)
                    return;
                this.callBase.apply(this, arguments)
            },
            _shouldAttachHoldEvent: function() {
                return this.callBase.apply(this, arguments) || this._editProvider.holdHandlerExists()
            },
            _handleItemHold: function(e) {
                var $itemElement = $(e.currentTarget);
                if ($itemElement.is(".dx-state-disabled, .dx-state-disabled *"))
                    return;
                var handledByEditProvider = this.option("editEnabled") && this._editProvider.handleHold($itemElement, e);
                if (handledByEditProvider)
                    return;
                this.callBase.apply(this, arguments)
            },
            _getItemRenderer: function() {
                if (this.option("editEnabled") && this._editProvider.isRenderingByRenderer())
                    return this._editProvider.getItemRenderer();
                return this.callBase.apply(this, arguments)
            },
            _getItemTemplateName: function(itemData) {
                if (this.option("editEnabled") && this._editProvider.isRenderingByTemplate(itemData))
                    return this._editProvider.getItemTemplateName(itemData);
                return this.callBase.apply(this, arguments)
            },
            _postprocessRenderItem: function(args) {
                this.callBase.apply(this, arguments);
                var $itemElement = $(args.itemElement);
                if (this._isItemSelected(this._editStrategy.getNormalizedIndex($itemElement)))
                    $itemElement.addClass(LIST_ITEM_SELECTED_CLASS);
                if (this.option("editEnabled") && this._editProvider.isModifyingByDecorators(args.itemData))
                    this._editProvider.modifyItemElement(args)
            },
            _dispose: function() {
                this._disposeEditProvider();
                this.callBase.apply(this, arguments)
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"rtlEnabled":
                        this._refreshEditProvider();
                        this.callBase.apply(this, arguments);
                        break;
                    case"items":
                        this._clearSelectedItems();
                        this.callBase.apply(this, arguments);
                        break;
                    case"grouped":
                        this._clearSelectedItems();
                        delete this._renderingGroupIndex;
                        this._initEditStrategy(value);
                        this.callBase.apply(this, arguments);
                        break;
                    case"editEnabled":
                        this._clearSelectedItems();
                        this._invalidate();
                        break;
                    case"editConfig":
                        this._refreshEditProvider();
                        this._invalidate();
                        break;
                    case"selectionMode":
                        this._refreshEditProvider();
                        this._invalidate();
                        break;
                    case"selectedItems":
                        this._normalizeSelectedItems();
                        break;
                    case"itemDeleteAction":
                    case"itemSelectAction":
                    case"itemUnselectAction":
                    case"itemReorderAction":
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _isItemSelected: function(index) {
                return $.inArray(index, this._selectedItemIndices) > -1
            },
            _normalizeSelectedItems: function() {
                if (this.option("selectionMode") === "single") {
                    var newSelection = this._editStrategy.selectedItemIndecies(this.option("selectedItems"));
                    if (newSelection.length > 1) {
                        var normalizedSelection = [newSelection[0]];
                        this.option("selectedItems", this._editStrategy.fetchSelectedItems(normalizedSelection))
                    }
                    else
                        this._updateSelectedItems()
                }
                else
                    this._updateSelectedItems()
            },
            _updateSelectedItems: function() {
                var that = this,
                    newSelection = this._editStrategy.selectedItemIndecies();
                var unselected = removeDublicates(this._selectedItemIndices, newSelection);
                $.each(unselected, function(_, normalizedIndex) {
                    that._unselectItem(normalizedIndex)
                });
                var selected = removeDublicates(newSelection, this._selectedItemIndices);
                $.each(selected, function(_, normalizedIndex) {
                    that._selectItem(normalizedIndex)
                })
            },
            _updateSelectionAfterDelete: function(fromIndex) {
                var that = this,
                    itemIndex = $.inArray(fromIndex, this._selectedItemIndices);
                if (itemIndex > -1)
                    this._selectedItemIndices.splice(itemIndex, 1);
                this._editStrategy.updateSelectionAfterDelete(fromIndex);
                this.option("selectedItems", this._editStrategy.fetchSelectedItems())
            },
            _selectItem: function(normalizedIndex) {
                var $itemElement = this._editStrategy.getItemElement(normalizedIndex);
                if (this.option("editEnabled") && normalizedIndex > -1 && !this._isItemSelected(normalizedIndex)) {
                    $itemElement.addClass(LIST_ITEM_SELECTED_CLASS);
                    this._selectedItemIndices.push(normalizedIndex);
                    $itemElement.trigger("stateChanged");
                    this._handleItemEvent($itemElement, "itemSelectAction", {}, {excludeValidators: ["gesture", "disabled"]})
                }
            },
            _unselectItem: function(normalizedIndex) {
                var $itemElement = this._editStrategy.getItemElement(normalizedIndex),
                    itemSelectionIndex = $.inArray(normalizedIndex, this._selectedItemIndices);
                if (this.option("editEnabled") && itemSelectionIndex > -1) {
                    $itemElement.removeClass(LIST_ITEM_SELECTED_CLASS);
                    this._selectedItemIndices.splice(itemSelectionIndex, 1);
                    $itemElement.trigger("stateChanged");
                    this._handleItemEvent($itemElement, "itemUnselectAction", {}, {excludeValidators: ["gesture", "disabled"]})
                }
            },
            _deleteItemFromDS: function($item) {
                var that = this,
                    deferred = $.Deferred(),
                    disabledState = this.option("disabled"),
                    dataStore = this._dataSource.store();
                this.option("disabled", true);
                if (!dataStore.remove)
                    throw new Error("You have to implement 'remove' method in dataStore used by dxList to be able to delete items");
                dataStore.remove(dataStore.keyOf(this._getItemData($item))).done(function(key) {
                    if (key !== undefined)
                        deferred.resolveWith(that);
                    else
                        deferred.rejectWith(that)
                }).fail(function() {
                    deferred.rejectWith(that)
                });
                deferred.always(function() {
                    that.option("disabled", disabledState)
                });
                return deferred
            },
            _refreshLastPage: function() {
                this._expectLastItemLoading();
                return this._dataSource.load()
            },
            getFlatIndexByItemElement: function(itemElement) {
                return this._itemElements().index(itemElement)
            },
            getItemElementByFlatIndex: function(flatIndex) {
                var $itemElements = this._itemElements();
                if (flatIndex < 0 || flatIndex >= $itemElements.length)
                    return $();
                return $itemElements.eq(flatIndex)
            },
            getItemByIndex: function(index) {
                return this._getItemData(this._itemElements().eq(index))
            },
            deleteItem: function(itemElement) {
                var that = this,
                    deferred = $.Deferred(),
                    $item = this._editStrategy.getItemElement(itemElement),
                    index = this._editStrategy.getNormalizedIndex(itemElement),
                    changingOption;
                if (this.option("editEnabled") && index > -1) {
                    $item.addClass(LIST_ITEM_RESPONSE_WAIT_CLASS);
                    if (this._dataSource) {
                        changingOption = "dataSource";
                        deferred = this._deleteItemFromDS($item)
                    }
                    else {
                        changingOption = "items";
                        deferred.resolveWith(this)
                    }
                }
                else
                    deferred.rejectWith(this);
                deferred.done(function() {
                    $item.detach();
                    that._editStrategy.deleteItemAtIndex(index);
                    that.optionChanged.fireWith(that, [changingOption, that.option(changingOption)]);
                    that._updateSelectionAfterDelete(index);
                    that._handleItemEvent($item, "itemDeleteAction", {}, {excludeValidators: ["gesture", "disabled"]});
                    that._renderEmptyMessage()
                }).fail(function() {
                    $item.removeClass(LIST_ITEM_RESPONSE_WAIT_CLASS)
                });
                if (this._isLastPage() || this.option("grouped"))
                    return deferred.promise();
                var pageRefreshDeffered = $.Deferred();
                deferred.done(function() {
                    that._refreshLastPage().done(function() {
                        pageRefreshDeffered.resolveWith(that)
                    })
                }).fail(function() {
                    pageRefreshDeffered.rejectWith(that)
                });
                return pageRefreshDeffered.promise()
            },
            isItemSelected: function(itemElement) {
                return this._isItemSelected(this._editStrategy.getNormalizedIndex(itemElement))
            },
            selectItem: function(itemElement) {
                if (!this.option("editEnabled"))
                    return;
                var itemIndex = this._editStrategy.getNormalizedIndex(itemElement);
                if (itemIndex === -1)
                    return;
                var itemSelectionIndex = $.inArray(itemIndex, this._selectedItemIndices);
                if (itemSelectionIndex !== -1)
                    return;
                if (this.option("selectionMode") === "single")
                    this.option("selectedItems", this._editStrategy.fetchSelectedItems([itemIndex]));
                else {
                    var newSelectedIndices = this._selectedItemIndices.slice();
                    newSelectedIndices.push(itemIndex);
                    this.option("selectedItems", this._editStrategy.fetchSelectedItems(newSelectedIndices))
                }
            },
            unselectItem: function(itemElement) {
                if (!this.option("editEnabled"))
                    return;
                var itemIndex = this._editStrategy.getNormalizedIndex(itemElement);
                if (itemIndex === -1)
                    return;
                var itemSelectionIndex = $.inArray(itemIndex, this._selectedItemIndices);
                if (itemSelectionIndex === -1)
                    return;
                var newSelectedIndices = this._selectedItemIndices.slice();
                newSelectedIndices.splice(itemSelectionIndex, 1);
                this.option("selectedItems", this._editStrategy.fetchSelectedItems(newSelectedIndices))
            },
            reorderItem: function(itemElement, toItemElement) {
                var deferred = $.Deferred(),
                    that = this,
                    strategy = this._editStrategy,
                    $movingItem = strategy.getItemElement(itemElement),
                    $destinationItem = strategy.getItemElement(toItemElement),
                    movingIndex = strategy.getNormalizedIndex(itemElement),
                    destinationIndex = strategy.getNormalizedIndex(toItemElement),
                    changingOption;
                var canMoveItems = movingIndex > -1 && destinationIndex > -1 && movingIndex !== destinationIndex;
                if (this.option("editEnabled") && canMoveItems)
                    if (this._dataSource) {
                        changingOption = "dataSource";
                        deferred.resolveWith(this)
                    }
                    else {
                        changingOption = "items";
                        deferred.resolveWith(this)
                    }
                else
                    deferred.rejectWith(this);
                return deferred.promise().done(function() {
                        $destinationItem[strategy.itemPlacementFunc(movingIndex, destinationIndex)]($movingItem);
                        var newSelectedItems = strategy.getSelectedItemsAfterReorderItem(movingIndex, destinationIndex);
                        strategy.moveItemAtIndexToIndex(movingIndex, destinationIndex);
                        that._selectedItemIndices = strategy.selectedItemIndecies(newSelectedItems);
                        that.option("selectedItems", strategy.fetchSelectedItems());
                        that.optionChanged.fireWith(that, [changingOption, that.option(changingOption)]);
                        that._handleItemEvent($movingItem, "itemReorderAction", {
                            fromIndex: strategy.getIndex(movingIndex),
                            toIndex: strategy.getIndex(destinationIndex)
                        }, {excludeValidators: ["gesture", "disabled"]})
                    })
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.gallery.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            fx = DX.fx,
            translator = DX.translator,
            GALLERY_CLASS = "dx-gallery",
            GALLERY_WRAPPER_CLASS = GALLERY_CLASS + "-wrapper",
            GALLERY_LOOP_CLASS = "dx-gallery-loop",
            GALLERY_ITEM_CONTAINER_CLASS = GALLERY_CLASS + "-container",
            GALLERY_ACTIVE_CLASS = GALLERY_CLASS + "-active",
            GALLERY_ITEM_CLASS = GALLERY_CLASS + "-item",
            GALLERY_LOOP_ITEM_CLASS = GALLERY_ITEM_CLASS + "-loop",
            GALLERY_ITEM_SELECTOR = "." + GALLERY_ITEM_CLASS,
            GALLERY_ITEM_SELECTED_CLASS = GALLERY_ITEM_CLASS + "-selected",
            GALLERY_INDICATOR_CLASS = GALLERY_CLASS + "-indicator",
            GALLERY_INDICATOR_ITEM_CLASS = GALLERY_INDICATOR_CLASS + "-item",
            GALLERY_INDICATOR_ITEM_SELECTOR = "." + GALLERY_INDICATOR_ITEM_CLASS,
            GALLERY_INDICATOR_ITEM_SELECTED_CLASS = GALLERY_INDICATOR_ITEM_CLASS + "-selected",
            GALLERY_ITEM_DATA_KEY = "dxGalleryItemData";
        DX.registerComponent("dxGalleryNavButton", ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    direction: "next",
                    clickAction: null
                })
            },
            _render: function() {
                this.callBase();
                var that = this,
                    $element = this._element(),
                    eventName = events.addNamespace("dxclick", this.NAME);
                $element.addClass(GALLERY_CLASS + "-nav-button-" + this.option("direction")).off(eventName).on(eventName, function(e) {
                    that._createActionByOption("clickAction")({jQueryEvent: e})
                })
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"clickAction":
                    case"direction":
                        this._invalidate();
                        break;
                    default:
                        this.callBase(name, value, prevValue)
                }
            }
        }));
        DX.registerComponent("dxGallery", ui.CollectionContainerWidget.inherit({
            _activeStateUnit: GALLERY_ITEM_SELECTOR,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    activeStateEnabled: false,
                    animationDuration: 400,
                    loop: false,
                    swipeEnabled: true,
                    indicatorEnabled: true,
                    showIndicator: true,
                    selectedIndex: 0,
                    slideshowDelay: 0,
                    showNavButtons: false
                })
            },
            _dataSourceOptions: function() {
                return {paginate: false}
            },
            _itemContainer: function() {
                return this._$container
            },
            _itemClass: function() {
                return GALLERY_ITEM_CLASS
            },
            _itemDataKey: function() {
                return GALLERY_ITEM_DATA_KEY
            },
            _itemWidth: function() {
                if (!this._itemWidthCache)
                    this._itemWidthCache = this._itemElements().first().outerWidth();
                return this._itemWidthCache
            },
            _clearItemWidthCache: function() {
                delete this._itemWidthCache
            },
            _itemsCount: function() {
                return (this.option("items") || []).length
            },
            _offsetDirection: function() {
                return this.option("rtlEnabled") ? -1 : 1
            },
            _itemRenderDefault: function(item, index, itemElement) {
                itemElement.append($("<img />").attr("src", String(item)))
            },
            _renderSelectedIndex: $.noop,
            _render: function() {
                this._element().addClass(GALLERY_CLASS);
                this._element().toggleClass(GALLERY_LOOP_CLASS, this.option("loop"));
                this._renderDragHandler();
                this._renderWrapper();
                this._renderItemContainer();
                this.callBase();
                this._renderContainerPosition();
                this._renderItemPositions();
                this._renderIndicator();
                this._renderSelectedIndicatorItem();
                this._renderUserInteraction();
                this._renderNavButtons();
                this._setupSlideShow();
                this._reviseDimensions()
            },
            _dimensionChanged: function() {
                this._clearItemWidthCache();
                this._renderDuplicateItems();
                this._renderItemPositions();
                this._renderContainerPosition()
            },
            _renderDragHandler: function() {
                var eventName = events.addNamespace("dragstart", this.NAME);
                this._element().off(eventName).on(eventName, "img", function() {
                    return false
                })
            },
            _renderWrapper: function() {
                if (this._$wrapper)
                    return;
                this._$wrapper = $("<div />").addClass(GALLERY_WRAPPER_CLASS).appendTo(this._element())
            },
            _renderItems: function(items) {
                this.callBase(items);
                this._renderDuplicateItems()
            },
            _renderItemContainer: function() {
                if (this._$container)
                    return;
                this._$container = $("<div>").addClass(GALLERY_ITEM_CONTAINER_CLASS).appendTo(this._$wrapper)
            },
            _renderDuplicateItems: function() {
                var items = this.option("items") || [],
                    itemsCount = items.length;
                if (!itemsCount)
                    return;
                this._element().find("." + GALLERY_LOOP_ITEM_CLASS).remove();
                var itemsPerPage = this._element().width() / this._itemWidth(),
                    duplicateCount = Math.min(itemsPerPage, itemsCount);
                for (var i = 0; i < duplicateCount; i++)
                    this._renderItem(0, items[i]).addClass(GALLERY_LOOP_ITEM_CLASS);
                this._renderItem(0, items[this._itemsCount() - 1]).addClass(GALLERY_LOOP_ITEM_CLASS)
            },
            _renderItemPositions: function() {
                var itemWidth = this._itemWidth(),
                    loopItemsCount = this._element().find("." + GALLERY_LOOP_ITEM_CLASS).length,
                    lastItemDuplicateIndex = this._itemsCount() + loopItemsCount - 1,
                    offsetDirection = this._offsetDirection();
                this._itemElements().each(function(index) {
                    var realIndex = index;
                    if (index === lastItemDuplicateIndex)
                        realIndex = -1;
                    translator.move($(this), {left: offsetDirection * realIndex * itemWidth})
                })
            },
            _renderContainerPosition: function(offset, animate) {
                offset = offset || 0;
                var that = this,
                    itemWidth = this._itemWidth(),
                    selectedIndex = this.option("selectedIndex"),
                    targetIndex = offset - selectedIndex,
                    targetPosition = this._offsetDirection() * targetIndex * itemWidth,
                    positionReady;
                if (animate) {
                    that._startSwipe();
                    positionReady = that._animate(targetPosition).done($.proxy(that._endSwipe, that))
                }
                else {
                    translator.move(this._$container, {left: targetPosition});
                    positionReady = $.Deferred().resolveWith(that)
                }
                return positionReady.promise()
            },
            _startSwipe: function() {
                this._element().addClass(GALLERY_ACTIVE_CLASS)
            },
            _endSwipe: function() {
                this._element().removeClass(GALLERY_ACTIVE_CLASS)
            },
            _animate: function(targetPosition, extraConfig) {
                var that = this,
                    animationComplete = $.Deferred();
                fx.animate(this._$container, $.extend({
                    type: "slide",
                    to: {left: targetPosition},
                    duration: that.option("animationDuration"),
                    complete: function() {
                        animationComplete.resolveWith(that)
                    }
                }, extraConfig || {}));
                return animationComplete
            },
            _reviseDimensions: function() {
                var that = this,
                    $firstItem = that._itemElements().first();
                if (!$firstItem)
                    return;
                if (!that.option("height"))
                    that.option("height", $firstItem.outerHeight());
                if (!that.option("width"))
                    that.option("width", $firstItem.outerWidth());
                this._dimensionChanged()
            },
            _renderIndicator: function() {
                if (!this.option("showIndicator")) {
                    this._cleanIndicators();
                    return
                }
                var indicator = this._$indicator = $("<div>").addClass(GALLERY_INDICATOR_CLASS).appendTo(this._$wrapper);
                $.each(this.option("items") || [], function() {
                    $("<div>").addClass(GALLERY_INDICATOR_ITEM_CLASS).appendTo(indicator)
                })
            },
            _cleanIndicators: function() {
                if (this._$indicator)
                    this._$indicator.remove()
            },
            _renderSelectedIndicatorItem: function() {
                var selectedIndex = this.option("selectedIndex");
                this._itemElements().removeClass(GALLERY_ITEM_SELECTED_CLASS).eq(selectedIndex).addClass(GALLERY_ITEM_SELECTED_CLASS);
                this._element().find(GALLERY_INDICATOR_ITEM_SELECTOR).removeClass(GALLERY_INDICATOR_ITEM_SELECTED_CLASS).eq(selectedIndex).addClass(GALLERY_INDICATOR_ITEM_SELECTED_CLASS)
            },
            _renderUserInteraction: function() {
                var that = this,
                    rootElement = that._element(),
                    swipeEnabled = that.option("swipeEnabled") && this._itemsCount() > 1,
                    cursor = swipeEnabled ? "pointer" : "default";
                rootElement.dxSwipeable({
                    disabled: this.option("disabled") || !swipeEnabled,
                    startAction: $.proxy(that._handleSwipeStart, that),
                    updateAction: $.proxy(that._handleSwipeUpdate, that),
                    endAction: $.proxy(that._handleSwipeEnd, that),
                    itemSizeFunc: $.proxy(that._itemWidth, that)
                });
                var indicatorSelectAction = this._createAction(this._handleIndicatorSelect);
                rootElement.find(GALLERY_INDICATOR_ITEM_SELECTOR).off(events.addNamespace("dxclick", this.NAME)).on(events.addNamespace("dxclick", this.NAME), function(e) {
                    indicatorSelectAction({jQueryEvent: e})
                })
            },
            _handleIndicatorSelect: function(args) {
                var e = args.jQueryEvent,
                    instance = args.component;
                if (events.needSkipEvent(e))
                    return;
                if (!instance.option("indicatorEnabled"))
                    return;
                var index = $(e.target).index();
                instance._renderContainerPosition(instance.option("selectedIndex") - index, true).done(function() {
                    this._suppressRenderItemPositions = true;
                    instance.option("selectedIndex", index)
                })
            },
            _renderNavButtons: function() {
                var that = this;
                if (!that.option("showNavButtons")) {
                    that._cleanNavButtons();
                    return
                }
                that._prevNavButton = $("<div />").dxGalleryNavButton({
                    direction: "prev",
                    clickAction: function() {
                        that.prevItem(true)
                    }
                }).appendTo(this._$wrapper);
                that._nextNavButton = $("<div />").dxGalleryNavButton({
                    direction: "next",
                    clickAction: function() {
                        that.nextItem(true)
                    }
                }).appendTo(this._$wrapper);
                this._renderNavButtonsVisibility()
            },
            _cleanNavButtons: function() {
                if (this._prevNavButton)
                    this._prevNavButton.remove();
                if (this._prevNavButton)
                    this._nextNavButton.remove()
            },
            _renderNavButtonsVisibility: function() {
                if (!this.option("showNavButtons"))
                    return;
                var selectedIndex = this.option("selectedIndex"),
                    loop = this.option("loop"),
                    itemsCount = this._itemsCount();
                this._prevNavButton.show();
                this._nextNavButton.show();
                if (loop)
                    return;
                var nextHidden = itemsCount < 2 || selectedIndex === itemsCount - 1,
                    prevHidden = itemsCount < 2 || selectedIndex === 0;
                if (prevHidden)
                    this._prevNavButton.hide();
                if (nextHidden)
                    this._nextNavButton.hide()
            },
            _setupSlideShow: function() {
                var that = this,
                    slideshowDelay = that.option("slideshowDelay");
                if (!slideshowDelay)
                    return;
                clearTimeout(that._slideshowTimer);
                that._slideshowTimer = setTimeout(function() {
                    if (that._userInteraction) {
                        that._setupSlideShow();
                        return
                    }
                    that.nextItem(true).done(that._setupSlideShow)
                }, slideshowDelay)
            },
            _handleSwipeStart: function(e) {
                var itemsCount = this._itemsCount();
                if (!itemsCount) {
                    e.jQueryEvent.cancel = true;
                    return
                }
                this._stopItemAnimations();
                this._startSwipe();
                this._userInteraction = true;
                if (!this.option("loop")) {
                    var selectedIndex = this.option("selectedIndex"),
                        startOffset = itemsCount - selectedIndex - 1,
                        endOffset = selectedIndex,
                        rtlEnabled = this.option("rtlEnabled");
                    e.jQueryEvent.maxLeftOffset = rtlEnabled ? endOffset : startOffset;
                    e.jQueryEvent.maxRightOffset = rtlEnabled ? startOffset : endOffset
                }
            },
            _stopItemAnimations: function() {
                if (fx.isAnimating(this._$container))
                    fx.stop(this._$container, true)
            },
            _handleSwipeUpdate: function(e) {
                this._renderContainerPosition(this._offsetDirection() * e.jQueryEvent.offset)
            },
            _handleSwipeEnd: function(e) {
                var targetOffset = e.jQueryEvent.targetOffset * this._offsetDirection();
                this._renderContainerPosition(targetOffset, true).done(function() {
                    var selectedIndex = this.option("selectedIndex"),
                        newIndex = this._fitIndex(selectedIndex - targetOffset);
                    this._suppressRenderItemPositions = true;
                    this.option("selectedIndex", newIndex);
                    this._renderContainerPosition();
                    this._userInteraction = false;
                    this._setupSlideShow()
                })
            },
            _flipIndex: function(index) {
                if (!this.option("loop"))
                    return index;
                var itemsCount = this._itemsCount();
                index = index % itemsCount;
                if (index > (itemsCount + 1) / 2)
                    index -= itemsCount;
                if (index < -(itemsCount - 1) / 2)
                    index += itemsCount;
                return index
            },
            _fitIndex: function(index) {
                if (!this.option("loop"))
                    return index;
                var itemsCount = this._itemsCount();
                index = index % itemsCount;
                if (index < 0)
                    index += itemsCount;
                return index
            },
            _clean: function() {
                this.callBase();
                this._cleanIndicators();
                this._cleanNavButtons()
            },
            _dispose: function() {
                clearTimeout(this._slideshowTimer);
                this.callBase()
            },
            _handleSelectedIndexChanged: function() {
                if (!this._suppressRenderItemPositions)
                    this._renderContainerPosition();
                this._suppressRenderItemPositions = false;
                this._renderSelectedIndicatorItem();
                this._renderNavButtonsVisibility()
            },
            _visibilityChanged: function(visible) {
                if (visible)
                    this._dimensionChanged()
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"width":
                        this.callBase.apply(this, arguments);
                        this._dimensionChanged();
                        break;
                    case"animationDuration":
                        this._renderNavButtonsVisibility();
                        break;
                    case"loop":
                        this._element().toggleClass(GALLERY_LOOP_CLASS, value);
                        this._renderNavButtonsVisibility();
                        return;
                    case"selectedIndex":
                        this._handleSelectedIndexChanged();
                        this.callBase.apply(this, arguments);
                        return;
                    case"showIndicator":
                        this._renderIndicator();
                        return;
                    case"showNavButtons":
                        this._renderNavButtons();
                        return;
                    case"slideshowDelay":
                        this._setupSlideShow();
                        return;
                    case"swipeEnabled":
                    case"indicatorEnabled":
                        this._renderUserInteraction();
                        return;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            goToItem: function(itemIndex, animation) {
                var d = new $.Deferred,
                    selectedIndex = this.option("selectedIndex"),
                    itemsCount = this._itemsCount();
                itemIndex = this._fitIndex(itemIndex);
                if (itemIndex > itemsCount - 1 || itemIndex < 0)
                    return d.resolveWith(this).promise();
                this._renderContainerPosition(selectedIndex - itemIndex, animation).done(function() {
                    this._suppressRenderItemPositions = true;
                    this.option("selectedIndex", itemIndex);
                    d.resolveWith(this)
                });
                return d.promise()
            },
            prevItem: function(animation) {
                return this.goToItem(this.option("selectedIndex") - 1, animation)
            },
            nextItem: function(animation) {
                return this.goToItem(this.option("selectedIndex") + 1, animation)
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.overlay.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            fx = DX.fx,
            translator = DX.translator;
        var OVERLAY_CLASS = "dx-overlay",
            OVERLAY_WRAPPER_CLASS = "dx-overlay-wrapper",
            OVERLAY_CONTENT_CLASS = "dx-overlay-content",
            OVERLAY_SHADER_CLASS = "dx-overlay-shader",
            OVERLAY_MODAL_CLASS = "dx-overlay-modal",
            RTL_DIRECTION_CLASS = "dx-rtl",
            ACTIONS = ["showingAction", "shownAction", "hidingAction", "hiddenAction", "positioningAction", "positionedAction"],
            LAST_Z_INDEX = 1000,
            DISABLED_STATE_CLASS = "dx-state-disabled";
        var realDevice = DX.devices.real(),
            android4_0nativeBrowser = realDevice.platform === "android" && /^4\.0(\.\d)?/.test(realDevice.version.join(".")) && navigator.userAgent.indexOf("Chrome") === -1;
        var forceRepaint = function($element) {
                $element.width();
                if (android4_0nativeBrowser) {
                    var $parents = $element.parents(),
                        inScrollView = $parents.is(".dx-scrollable-native");
                    if (!inScrollView) {
                        $parents.css("backface-visibility", "hidden");
                        $parents.css("backface-visibility");
                        $parents.css("backface-visibility", "visible")
                    }
                }
            };
        var getElement = function(value) {
                return $(value instanceof $.Event ? value.target : value)
            };
        DX.registerComponent("dxOverlay", ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    activeStateEnabled: false,
                    visible: false,
                    deferRendering: true,
                    shading: true,
                    shadingColor: "",
                    position: {
                        my: "center",
                        at: "center",
                        of: window
                    },
                    width: function() {
                        return $(window).width() * 0.8
                    },
                    height: function() {
                        return $(window).height() * 0.8
                    },
                    animation: {
                        show: {
                            type: "pop",
                            duration: 400
                        },
                        hide: {
                            type: "pop",
                            duration: 400,
                            to: {
                                opacity: 0,
                                scale: 0
                            },
                            from: {
                                opacity: 1,
                                scale: 1
                            }
                        }
                    },
                    closeOnOutsideClick: false,
                    showingAction: null,
                    shownAction: null,
                    hidingAction: null,
                    hiddenAction: null,
                    contentTemplate: "template",
                    targetContainer: undefined,
                    hideTopOverlayHandler: undefined,
                    closeOnTargetScroll: false,
                    positioningAction: null,
                    positionedAction: null
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function(device) {
                                var realDevice = DX.devices.real(),
                                    realPlatform = realDevice.platform,
                                    realVersion = realDevice.version;
                                return realPlatform === "android" && (realVersion[0] < 4 || realVersion[0] == 4 && realVersion[1] <= 1)
                            },
                            options: {animation: {
                                    show: {
                                        type: "fade",
                                        duration: 400
                                    },
                                    hide: {
                                        type: "fade",
                                        duration: 400,
                                        to: {opacity: 0},
                                        from: {opacity: 1}
                                    }
                                }}
                        }])
            },
            _optionsByReference: function() {
                return $.extend(this.callBase(), {animation: true})
            },
            _wrapper: function() {
                return this._$wrapper
            },
            _container: function() {
                return this._$container
            },
            _init: function() {
                this.callBase();
                this._initActions();
                this._initCloseOnOutsideClickHandler();
                this._$wrapper = $("<div>").addClass(OVERLAY_WRAPPER_CLASS);
                this._$container = $("<div>").addClass(OVERLAY_CONTENT_CLASS);
                var $element = this._element();
                this._$wrapper.addClass($element.attr("class"));
                $element.addClass(OVERLAY_CLASS);
                this._$wrapper.on("MSPointerDown", $.noop)
            },
            _clean: $.noop,
            _initOptions: function(options) {
                this._initTargetContainer(options.targetContainer);
                this._initHideTopOverlayHandler(options.hideTopOverlayHandler);
                this.callBase(options)
            },
            _initTargetContainer: function(targetContainer) {
                targetContainer = targetContainer === undefined ? DX.overlayTargetContainer() : targetContainer;
                var $element = this._element(),
                    $targetContainer = $element.closest(targetContainer);
                if (!$targetContainer.length)
                    $targetContainer = $(targetContainer).first();
                this._$targetContainer = $targetContainer.length ? $targetContainer : $element.parent()
            },
            _targetContainer: function() {
                return this._$targetContainer
            },
            _initHideTopOverlayHandler: function(handler) {
                this._hideTopOverlayHandler = handler !== undefined ? handler : $.proxy(this._defaultHideTopOverlayHandler, this)
            },
            _defaultHideTopOverlayHandler: function() {
                this.hide()
            },
            _initActions: function() {
                this._actions = {};
                $.each(ACTIONS, $.proxy(function(_, action) {
                    this._actions[action] = this._createActionByOption(action) || $.noop
                }, this))
            },
            _visibilityChanged: function(visible) {
                if (visible)
                    this._dimensionChanged()
            },
            _dimensionChanged: function() {
                this._renderGeometry()
            },
            _initCloseOnOutsideClickHandler: function() {
                this._documentDownHandler = $.proxy(function() {
                    this._handleDocumentDown.apply(this, arguments)
                }, this)
            },
            _handleDocumentDown: function(e) {
                if (LAST_Z_INDEX !== this._zIndex)
                    return;
                var closeOnOutsideClick = this.option("closeOnOutsideClick");
                if ($.isFunction(closeOnOutsideClick))
                    closeOnOutsideClick = closeOnOutsideClick(e);
                if (closeOnOutsideClick) {
                    var $container = this._$container,
                        outsideClick = !$container.is(e.target) && !$.contains($container.get(0), e.target);
                    if (outsideClick) {
                        e.preventDefault();
                        this.hide()
                    }
                }
            },
            _renderVisibilityAnimate: function(visible) {
                if (visible)
                    this._showTimestamp = $.now();
                this._stopAnimation();
                this._updateRegistration(visible);
                if (visible)
                    return this._makeVisible();
                else
                    return this._makeHidden()
            },
            _updateRegistration: function(enabled) {
                if (enabled) {
                    if (!this._zIndex)
                        this._zIndex = ++LAST_Z_INDEX
                }
                else if (this._zIndex) {
                    --LAST_Z_INDEX;
                    delete this._zIndex
                }
            },
            _makeVisible: function() {
                var that = this,
                    deferred = $.Deferred(),
                    animation = that.option("animation") || {},
                    showAnimation = animation.show,
                    completeShowAnimation = showAnimation && showAnimation.complete || $.noop;
                if (showAnimation && showAnimation.to) {
                    showAnimation = $.extend({type: "slide"}, showAnimation);
                    $.extend(showAnimation.to, {position: this.option("position")})
                }
                if (this._isHidingActionCancelled) {
                    delete this._isHidingActionCancelled;
                    deferred.resolve()
                }
                else {
                    this._actions.showingAction();
                    this._toggleVisibility(true);
                    this._$wrapper.css("z-index", this._zIndex);
                    this._$container.css("z-index", this._zIndex);
                    DX.utils.triggerShownEvent(that.content());
                    this._animate(showAnimation, function() {
                        completeShowAnimation.apply(this, arguments);
                        that._actions.shownAction();
                        deferred.resolve()
                    })
                }
                return deferred.promise()
            },
            _makeHidden: function() {
                var that = this,
                    deferred = $.Deferred(),
                    animation = this.option("animation") || {},
                    hideAnimation = animation.hide,
                    completeHideAnimation = hideAnimation && hideAnimation.complete || $.noop;
                var hidingArgs = {cancel: false};
                this._actions.hidingAction(hidingArgs);
                if (hidingArgs.cancel) {
                    this._isHidingActionCancelled = true;
                    this.option("visible", true);
                    deferred.resolve()
                }
                else {
                    this._toggleShading(false);
                    DX.utils.triggerHidingEvent(that.content());
                    this._animate(hideAnimation, function() {
                        that._toggleVisibility(false);
                        completeHideAnimation.apply(this, arguments);
                        that._actions.hiddenAction();
                        deferred.resolve()
                    })
                }
                return deferred.promise()
            },
            _animate: function(animation, completeCallback) {
                if (animation)
                    fx.animate(this._$container, $.extend({}, animation, {complete: completeCallback}));
                else
                    completeCallback()
            },
            _stopAnimation: function() {
                fx.stop(this._$container, true)
            },
            _toggleVisibility: function(visible) {
                this._stopAnimation();
                this.callBase.apply(this, arguments);
                this._$container.toggle(visible);
                this._toggleShading(visible);
                this._toggleSubscriptions(visible);
                this._updateRegistration(visible);
                if (visible) {
                    this._renderContent();
                    this._moveToTargetContainer();
                    this._renderGeometry()
                }
                else
                    this._moveFromTargetContainer()
            },
            _toggleShading: function(visible) {
                this._$wrapper.toggleClass(OVERLAY_MODAL_CLASS, this.option("shading") && !this.option("targetContainer"));
                this._$wrapper.toggleClass(OVERLAY_SHADER_CLASS, visible && this.option("shading"));
                this._$wrapper.css("background-color", this.option("shading") ? this.option("shadingColor") : "")
            },
            _toggleSubscriptions: function(enabled) {
                this._toggleHideTopOverlayCallback(enabled);
                this._toggleDocumentDownHandler(enabled);
                this._toggleParentsScrollSubscription(enabled)
            },
            _toggleHideTopOverlayCallback: function(subscribe) {
                if (!this._hideTopOverlayHandler)
                    return;
                if (subscribe)
                    DX.hideTopOverlayCallback.add(this._hideTopOverlayHandler);
                else
                    DX.hideTopOverlayCallback.remove(this._hideTopOverlayHandler)
            },
            _toggleDocumentDownHandler: function(enabled) {
                var that = this,
                    eventName = events.addNamespace("dxpointerdown", that.NAME);
                if (enabled)
                    $(document).on(eventName, this._documentDownHandler);
                else
                    $(document).off(eventName, this._documentDownHandler)
            },
            _toggleParentsScrollSubscription: function(subscribe) {
                var position = this.option("position");
                if (!position || !position.of)
                    return;
                var that = this,
                    closeOnScroll = this.option("closeOnTargetScroll"),
                    $parents = getElement(position.of).parents().add(window);
                $parents.off(events.addNamespace("scroll", that.NAME));
                if (subscribe && closeOnScroll)
                    $parents.on(events.addNamespace("scroll", that.NAME), function(e) {
                        if (e.overlayProcessed)
                            return;
                        e.overlayProcessed = true;
                        var closeHandled = false;
                        if ($.isFunction(closeOnScroll))
                            closeHandled = closeOnScroll(e);
                        if (!closeHandled)
                            that.hide()
                    })
            },
            _renderContent: function() {
                if (this._contentAlreadyRendered || !this.option("visible") && this.option("deferRendering"))
                    return;
                this._contentAlreadyRendered = true;
                this.callBase()
            },
            _renderContentImpl: function(template) {
                var $element = this._element(),
                    contentTemplate = template || this._getTemplate(this.option("contentTemplate"));
                this._$container.append($element.contents()).appendTo($element);
                if (contentTemplate)
                    contentTemplate.render(this.content())
            },
            _fireContentReadyAction: function() {
                if (this.option("visible"))
                    this._moveToTargetContainer();
                this.callBase.apply(this, arguments)
            },
            _moveFromTargetContainer: function() {
                this._$container.appendTo(this._element());
                this._detachWrapperToTargetContainer()
            },
            _detachWrapperToTargetContainer: function() {
                this._$wrapper.detach()
            },
            _moveToTargetContainer: function() {
                this._attachWrapperToTargetContainer();
                this._$container.appendTo(this._$wrapper)
            },
            _attachWrapperToTargetContainer: function() {
                var $element = this._element();
                if (this._$targetContainer && !(this._$targetContainer[0] === $element.parent()[0]))
                    this._$wrapper.appendTo(this._$targetContainer);
                else
                    this._$wrapper.appendTo($element)
            },
            _renderGeometry: function() {
                if (this.option("visible"))
                    this._renderGeometryImpl()
            },
            _renderGeometryImpl: function() {
                this._stopAnimation();
                this._renderShading();
                this._renderDimensions();
                this._renderPosition()
            },
            _renderShading: function() {
                var $wrapper = this._$wrapper,
                    $targetContainer = this._getTargetContainer();
                $wrapper.css("position", $targetContainer.get(0) === window ? "fixed" : "absolute");
                if (this.option("shading"))
                    $wrapper.show();
                this._renderShadingDimensions();
                this._renderShadingPosition()
            },
            _renderShadingPosition: function() {
                if (this.option("shading")) {
                    var $targetContainer = this._getTargetContainer();
                    DX.position(this._$wrapper, {
                        my: "top left",
                        at: "top left",
                        of: $targetContainer
                    })
                }
            },
            _renderShadingDimensions: function() {
                if (this.option("shading")) {
                    var $targetContainer = this._getTargetContainer();
                    this._$wrapper.css({
                        width: $targetContainer.outerWidth(),
                        height: $targetContainer.outerHeight()
                    })
                }
            },
            _getTargetContainer: function() {
                var position = this.option("position"),
                    targetContainer = this.option("targetContainer"),
                    positionOf = position ? position.of : null;
                return getElement(targetContainer || positionOf)
            },
            _renderDimensions: function() {
                this._$container.outerWidth(this.option("width")).outerHeight(this.option("height"))
            },
            _renderPosition: function() {
                translator.resetPosition(this._$container);
                var position = this.option("position"),
                    containerPosition = DX.calculatePosition(this._$container, position);
                this._actions.positioningAction({position: containerPosition});
                var resultPosition = DX.position(this._$container, containerPosition);
                this._actions.positionedAction({position: resultPosition});
                forceRepaint(this._$container)
            },
            _dispose: function() {
                this._stopAnimation();
                this._toggleSubscriptions(false);
                this._updateRegistration(false);
                this._actions = null;
                this.callBase();
                this._$wrapper.remove();
                this._$container.remove()
            },
            _toggleDisabledState: function(value) {
                this.callBase.apply(this, arguments);
                this._$container.toggleClass(DISABLED_STATE_CLASS, value)
            },
            _toggleRTLDirection: function(rtl) {
                this._$container.toggleClass(RTL_DIRECTION_CLASS, rtl)
            },
            _optionChanged: function(name, value) {
                if ($.inArray(name, ACTIONS) > -1) {
                    this._initActions();
                    return
                }
                switch (name) {
                    case"shading":
                    case"shadingColor":
                        this._toggleShading(this.option("visible"));
                        break;
                    case"width":
                    case"height":
                    case"position":
                        this._renderGeometry();
                        break;
                    case"visible":
                        this._renderVisibilityAnimate(value).done($.proxy(function() {
                            if (!this._animateDeferred)
                                return;
                            this._animateDeferred.resolveWith(this);
                            delete this._animateDeferred
                        }, this));
                        break;
                    case"targetContainer":
                        this._initTargetContainer(value);
                        this._invalidate();
                        break;
                    case"deferRendering":
                    case"contentTemplate":
                        this._invalidate();
                        break;
                    case"closeOnOutsideClick":
                        this._toggleDocumentDownHandler(this.option("visible"));
                        break;
                    case"closeOnTargetScroll":
                        this._toggleParentsScrollSubscription(this.option("visible"));
                        break;
                    case"animation":
                        break;
                    case"rtlEnabled":
                        this._toggleRTLDirection(value);
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            toggle: function(showing) {
                showing = showing === undefined ? !this.option("visible") : showing;
                if (showing === this.option("visible"))
                    return $.Deferred().resolve().promise();
                var animateDeferred = $.Deferred();
                this._animateDeferred = animateDeferred;
                this.option("visible", showing);
                return animateDeferred.promise()
            },
            show: function() {
                return this.toggle(true)
            },
            hide: function() {
                return this.toggle(false)
            },
            content: function() {
                return this._$container
            },
            repaint: function() {
                this._renderGeometry()
            }
        }));
        ui.dxOverlay.__internals = {
            OVERLAY_CLASS: OVERLAY_CLASS,
            OVERLAY_WRAPPER_CLASS: OVERLAY_WRAPPER_CLASS,
            OVERLAY_CONTENT_CLASS: OVERLAY_CONTENT_CLASS,
            OVERLAY_SHADER_CLASS: OVERLAY_SHADER_CLASS,
            OVERLAY_MODAL_CLASS: OVERLAY_MODAL_CLASS
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.toast.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var TOAST_CLASS = "dx-toast",
            TOAST_CLASS_PREFIX = TOAST_CLASS + "-",
            TOAST_WRAPPER_CLASS = TOAST_CLASS_PREFIX + "wrapper",
            TOAST_CONTENT_CLASS = TOAST_CLASS_PREFIX + "content",
            TOAST_MESSAGE_CLASS = TOAST_CLASS_PREFIX + "message",
            TOAST_ICON_CLASS = TOAST_CLASS_PREFIX + "icon",
            WIDGET_NAME = "dxToast",
            toastTypes = ["info", "warning", "error", "success"];
        DX.registerComponent(WIDGET_NAME, ui.dxOverlay.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    message: "",
                    type: "info",
                    displayTime: 2000,
                    position: {
                        my: "bottom center",
                        at: "bottom center",
                        of: window,
                        offset: "0 -20"
                    },
                    animation: {
                        show: {
                            type: "fade",
                            duration: 400,
                            from: 0,
                            to: 1
                        },
                        hide: {
                            type: "fade",
                            duration: 400,
                            to: 0
                        }
                    },
                    shading: false,
                    height: "auto"
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: {platform: "win8"},
                            options: {
                                position: {
                                    my: "top center",
                                    at: "top center",
                                    of: window,
                                    offset: "0 0"
                                },
                                width: function() {
                                    return $(window).width()
                                }
                            }
                        }])
            },
            _renderContentImpl: function() {
                if (this.option("message"))
                    this._message = $("<div>").addClass(TOAST_MESSAGE_CLASS).text(this.option("message")).appendTo(this.content());
                if ($.inArray(this.option("type").toLowerCase(), toastTypes) > -1)
                    this.content().prepend($("<div>").addClass(TOAST_ICON_CLASS));
                this.callBase()
            },
            _render: function() {
                this.callBase();
                this._element().addClass(TOAST_CLASS);
                this._wrapper().addClass(TOAST_WRAPPER_CLASS);
                this._$container.addClass(TOAST_CLASS_PREFIX + String(this.option("type")).toLowerCase());
                this.content().addClass(TOAST_CONTENT_CLASS)
            },
            _makeVisible: function() {
                return this.callBase.apply(this, arguments).done($.proxy(function() {
                        clearTimeout(this._hideTimeout);
                        this._hideTimeout = setTimeout($.proxy(function() {
                            this.hide()
                        }, this), this.option("displayTime"))
                    }, this))
            },
            _dispose: function() {
                clearTimeout(this._hideTimeout);
                this.callBase()
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"type":
                        this._$container.removeClass(TOAST_CLASS_PREFIX + prevValue);
                        this._$container.addClass(TOAST_CLASS_PREFIX + String(value).toLowerCase());
                        break;
                    case"message":
                        if (this._message)
                            this._message.text(value);
                        break;
                    case"displayTime":
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        ui.dxToast.__internals = {
            TOAST_CLASS: TOAST_CLASS,
            TOAST_WRAPPER_CLASS: TOAST_WRAPPER_CLASS,
            TOAST_CONTENT_CLASS: TOAST_CONTENT_CLASS,
            TOAST_MESSAGE_CLASS: TOAST_MESSAGE_CLASS,
            TOAST_ICON_CLASS: TOAST_ICON_CLASS,
            TOAST_CLASS_PREFIX: TOAST_CLASS_PREFIX,
            WIDGET_NAME: WIDGET_NAME
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.popup.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            translator = DX.translator;
        var POPUP_CLASS = "dx-popup",
            POPUP_WRAPPER_CLASS = "dx-popup-wrapper",
            POPUP_FULL_SCREEN_CLASS = "dx-popup-fullscreen",
            POPUP_CONTENT_CLASS = "dx-popup-content",
            POPUP_DRAGGABLE_CLASS = "dx-popup-draggable",
            POPUP_TITLE_CLASS = "dx-popup-title",
            POPUP_TITLE_SELECTOR = "." + POPUP_TITLE_CLASS,
            POPUP_TITLE_CLOSEBUTTON_CLASS = "dx-closebutton",
            POPUP_TITLE_HAS_BUTTON_CLASS = "dx-popup-title-has-button",
            POPUP_BOTTOM_CLASS = "dx-popup-bottom",
            TOOLBAR_LEFT_CLASS = "dx-toolbar-before",
            TOOLBAR_RIGHT_CLASS = "dx-toolbar-after",
            OVERLAY_CONTENT_SELECTOR = ".dx-overlay-content",
            MIN_POPUP_STICK_SIZE = 40;
        var getButtonContainer = function(force) {
                var device = DX.devices.current(force),
                    container = {
                        cancel: {subclass: "dx-popup-cancel"},
                        clear: {subclass: "dx-popup-clear"},
                        done: {subclass: "dx-popup-done"}
                    };
                if (device.ios) {
                    $.extend(container.cancel, {
                        parent: POPUP_TITLE_SELECTOR,
                        wraperClass: TOOLBAR_LEFT_CLASS
                    });
                    $.extend(container.clear, {
                        parent: POPUP_TITLE_SELECTOR,
                        wraperClass: TOOLBAR_RIGHT_CLASS
                    });
                    $.extend(container.done, {wraperClass: POPUP_BOTTOM_CLASS})
                }
                if (device.android || device.platform === "desktop" || device.win8 || device.tizen || device.generic) {
                    $.extend(container.cancel, {wraperClass: POPUP_BOTTOM_CLASS});
                    $.extend(container.clear, {wraperClass: POPUP_BOTTOM_CLASS});
                    $.extend(container.done, {wraperClass: POPUP_BOTTOM_CLASS})
                }
                return container
            };
        DX.registerComponent("dxPopup", ui.dxOverlay.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    title: "",
                    showTitle: true,
                    fullScreen: false,
                    titleTemplate: "title",
                    dragEnabled: false,
                    cancelButton: null,
                    doneButton: null,
                    clearButton: null,
                    closeButton: null
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: {platform: "win8"},
                            options: {width: function() {
                                    return $(window).width()
                                }}
                        }, {
                            device: {
                                platform: "win8",
                                phone: true
                            },
                            options: {position: {
                                    my: "top center",
                                    at: "top center",
                                    of: window,
                                    offset: "0 0"
                                }}
                        }, {
                            device: [{platform: "ios"}, {platform: "ios7"}],
                            options: {animation: this._iosAnimation}
                        }, {
                            device: function(device) {
                                return DX.devices.real().platform === "generic" && device.platform === "generic"
                            },
                            options: {dragEnabled: true}
                        }])
            },
            _iosAnimation: {
                show: {
                    type: "slide",
                    duration: 400,
                    from: {position: {
                            my: "top",
                            at: "bottom",
                            of: window
                        }},
                    to: {position: {
                            my: "center",
                            at: "center",
                            of: window
                        }}
                },
                hide: {
                    type: "slide",
                    duration: 400,
                    from: {
                        opacity: 1,
                        position: {
                            my: "center",
                            at: "center",
                            of: window
                        }
                    },
                    to: {
                        opacity: 1,
                        position: {
                            my: "top",
                            at: "bottom",
                            of: window
                        }
                    }
                }
            },
            _init: function() {
                this.callBase();
                this._$content = this._container().wrapInner($("<div />").addClass(POPUP_CONTENT_CLASS)).children().eq(0)
            },
            _render: function() {
                this.callBase();
                this._element().addClass(POPUP_CLASS);
                this._wrapper().addClass(POPUP_WRAPPER_CLASS);
                this._container().toggleClass(POPUP_DRAGGABLE_CLASS, this.option("dragEnabled")).toggleClass(POPUP_FULL_SCREEN_CLASS, this.option("fullScreen"))
            },
            _renderContentImpl: function() {
                this.callBase(this._templates.content);
                this._renderTitle();
                this._renderDrag();
                this._renderButtons()
            },
            _renderTitle: function() {
                if (this.option("showTitle")) {
                    this._$title = this._$title || $("<div />").addClass(POPUP_TITLE_CLASS);
                    this._$title.empty();
                    this._element().append(this._$title);
                    if (this.option("title"))
                        this._defaultTitleRender();
                    else {
                        var titleTemplate = this._getTemplateByOption("titleTemplate");
                        if (titleTemplate)
                            titleTemplate.render(this._$title)
                    }
                    this._$title.prependTo(this._container())
                }
                else if (this._$title)
                    this._$title.detach()
            },
            _renderDrag: function() {
                if (!this._$title)
                    return;
                var startEventName = events.addNamespace("dxdragstart", this.NAME),
                    updateEventName = events.addNamespace("dxdrag", this.NAME);
                this._$title.off(startEventName).off(updateEventName);
                if (!this.option("dragEnabled"))
                    return;
                this._$title.on(startEventName, $.proxy(this._handleTitleDragStart, this)).on(updateEventName, $.proxy(this._handleTitleDragUpdate, this))
            },
            _handleTitleDragStart: function(e) {
                e.targetElements = [];
                this._prevOffset = {
                    x: 0,
                    y: 0
                };
                this._dragHandled = true;
                var position = translator.locate(this._container()),
                    allowedOffsets = this._allowedOffsets();
                e.maxLeftOffset = position.left + allowedOffsets.left;
                e.maxRightOffset = -position.left + allowedOffsets.right;
                e.maxTopOffset = position.top + allowedOffsets.top;
                e.maxBottomOffset = -position.top + allowedOffsets.bottom
            },
            _handleTitleDragUpdate: function(e) {
                var position = translator.locate(this._container()),
                    offset = e.offset,
                    prevOffset = this._prevOffset;
                translator.move(this._container(), {
                    left: position.left + (offset.x - prevOffset.x),
                    top: position.top + (offset.y - prevOffset.y)
                });
                this._prevOffset = offset
            },
            _allowedOffsets: function() {
                var $container = this._container(),
                    $targetContainer = this._targetContainer(),
                    containerWidth = $container.outerWidth(),
                    targetContainerWidth = $targetContainer.width(),
                    targetContainerHeight = $targetContainer.height();
                return {
                        top: 0,
                        bottom: targetContainerHeight - MIN_POPUP_STICK_SIZE,
                        left: containerWidth - MIN_POPUP_STICK_SIZE,
                        right: targetContainerWidth - MIN_POPUP_STICK_SIZE
                    }
            },
            _renderButtons: function() {
                var buttonsName = DX.devices.current().win8 ? ["Close", "Done", "Clear", "Cancel"] : ["Close", "Cancel", "Clear", "Done"];
                buttonsName.extractButtonName = this.option("rtlEnabled") ? buttonsName.pop : buttonsName.shift;
                while (!!buttonsName.length) {
                    var buttonName = buttonsName.extractButtonName();
                    this["_render" + buttonName + "Button"]()
                }
            },
            _defaultTitleRender: function() {
                this._$title.text(this.option("title"))
            },
            _renderCloseButton: function() {
                var renderButtonRequired = !this._templates.title && !!this.option("closeButton") && this.option("showTitle");
                this._$title && this._$title.toggleClass(POPUP_TITLE_HAS_BUTTON_CLASS, renderButtonRequired);
                if (renderButtonRequired) {
                    var clickAction = this._createButtonAction();
                    $("<div/>").addClass(POPUP_TITLE_CLOSEBUTTON_CLASS).on(ui.events.addNamespace("dxclick", this.NAME + "TitleCloseButton"), function(e) {
                        clickAction({jQueryEvent: e})
                    }).appendTo(this._$title)
                }
            },
            _renderCancelButton: function() {
                this._renderSpecificButton(this.option("cancelButton"), {
                    type: "cancel",
                    text: Globalize.localize("Cancel")
                })
            },
            _renderClearButton: function() {
                this._renderSpecificButton(this.option("clearButton"), {
                    type: "clear",
                    text: Globalize.localize("Clear")
                })
            },
            _renderDoneButton: function() {
                this._renderSpecificButton(this.option("doneButton"), {
                    type: "done",
                    text: Globalize.localize("Done")
                })
            },
            _renderSpecificButton: function(show, buttonConfig) {
                var renderParams = this._getRenderButtonParams(buttonConfig.type);
                this._removeButton(renderParams);
                this._wrapper().toggleClass(POPUP_CLASS + "-" + buttonConfig.type + "-visible", !!show);
                if (!show)
                    return;
                var userButtonOptions = this.option(buttonConfig.type + "Button");
                this._renderButton({
                    text: userButtonOptions.text || buttonConfig.text,
                    clickAction: this._createButtonAction(userButtonOptions.clickAction)
                }, renderParams)
            },
            _createButtonAction: function(clickAction) {
                return this._createAction(clickAction, {afterExecute: function(e) {
                            e.component.hide()
                        }})
            },
            _getRenderButtonParams: function(type) {
                return $.extend({}, getButtonContainer()[type])
            },
            _renderButton: function(buttonParams, renderParams) {
                var $button = $("<div/>").addClass(renderParams.subclass).dxButton(buttonParams),
                    $parentContainer = renderParams.parent ? this._container().find(renderParams.parent) : this._container(),
                    $buttonContainer = this._container().find("." + renderParams.wraperClass);
                if (!$buttonContainer.length)
                    $buttonContainer = $("<div/>").addClass(renderParams.wraperClass).appendTo($parentContainer);
                $button.appendTo($buttonContainer);
                this._container().find("." + POPUP_BOTTOM_CLASS).addClass(renderParams.subclass)
            },
            _removeButton: function(params) {
                var removeSelector = "." + (params.subclass || params.wraperClass);
                if (this.content())
                    this.content().removeClass(params.subclass);
                this._container().find(removeSelector).remove()
            },
            _renderGeometryImpl: function() {
                this.callBase.apply(this, arguments);
                this._setContentHeight()
            },
            _renderDimensions: function() {
                if (this.option("fullScreen"))
                    this._container().css({
                        width: "100%",
                        height: "100%"
                    });
                else
                    this.callBase.apply(this, arguments)
            },
            _renderShadingDimensions: function() {
                if (this.option("fullScreen"))
                    this._wrapper().css({
                        width: "100%",
                        height: "100%"
                    });
                else
                    this.callBase.apply(this, arguments)
            },
            _renderPosition: function() {
                if (this.option("fullScreen"))
                    translator.move(this._container(), {
                        top: 0,
                        left: 0
                    });
                else if (this._dragHandled) {
                    var $container = this._container(),
                        position = translator.locate($container),
                        allowedOffsets = this._allowedOffsets();
                    translator.move($container, {
                        top: Math.min(Math.max(-allowedOffsets.top, position.top), allowedOffsets.bottom),
                        left: Math.min(Math.max(-allowedOffsets.left, position.left), allowedOffsets.right)
                    })
                }
                else
                    this.callBase.apply(this, arguments)
            },
            _setContentHeight: function() {
                if (!this._$content)
                    return;
                var contentHeight = this._$container.height(),
                    hasBottomButtons = this.option("cancelButton") || this.option("doneButton") || this.option("clearButton"),
                    $bottomButtons = this._$wrapper.find(".dx-popup-bottom");
                if (this._$title)
                    contentHeight -= this._$title.outerHeight(true) || 0;
                if (hasBottomButtons) {
                    var bottomButtonsMargin = $bottomButtons.outerHeight(true) || 0;
                    contentHeight -= bottomButtonsMargin;
                    this._$content.css("margin-bottom", bottomButtonsMargin)
                }
                if (this.option("height") === "auto")
                    this._$content.css("height", "auto");
                else if (contentHeight > 0)
                    this._$content.css("height", contentHeight)
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"visible":
                        delete this._dragHandled;
                        this.callBase.apply(this, arguments);
                        break;
                    case"showTitle":
                    case"title":
                    case"titleTemplate":
                        this._renderTitle();
                        this._renderCloseButton();
                        this._setContentHeight();
                        break;
                    case"dragEnabled":
                        this._renderDrag();
                        break;
                    case"cancelButton":
                        this._renderCancelButton();
                        break;
                    case"clearButton":
                        this._renderClearButton();
                        break;
                    case"doneButton":
                        this._renderDoneButton();
                        break;
                    case"closeButton":
                        this._renderCloseButton();
                        break;
                    case"height":
                        this.callBase.apply(this, arguments);
                        this._setContentHeight();
                        break;
                    case"fullScreen":
                        this._container().toggleClass(POPUP_FULL_SCREEN_CLASS, value);
                        this._refresh();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            content: function() {
                return this._$content
            },
            container: function() {
                return this._$container
            }
        }));
        ui.dxPopup.__internals = {
            POPUP_CLASS: POPUP_CLASS,
            POPUP_WRAPPER_CLASS: POPUP_WRAPPER_CLASS,
            POPUP_CONTENT_CLASS: POPUP_CONTENT_CLASS,
            POPUP_FULL_SCREEN_CLASS: POPUP_FULL_SCREEN_CLASS,
            POPUP_TITLE_CLASS: POPUP_TITLE_CLASS,
            POPUP_TITLE_CLOSEBUTTON_CLASS: POPUP_TITLE_CLOSEBUTTON_CLASS,
            POPUP_TITLE_HAS_BUTTON_CLASS: POPUP_TITLE_HAS_BUTTON_CLASS
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.popover.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            fx = DX.fx;
        var POPOVER_CLASS = "dx-popover",
            POPOVER_WRAPPER_CLASS = "dx-popover-wrapper",
            POPOVER_ARROW_CLASS = "dx-popover-arrow",
            POPOVER_WITHOUT_TITLE_CLASS = "dx-popover-without-title",
            POSITION_FLIP_MAP = {
                left: "right",
                top: "bottom",
                right: "left",
                bottom: "top"
            },
            POSITION_ALIASES = {
                top: {
                    my: "bottom center",
                    at: "top center"
                },
                bottom: {
                    my: "top center",
                    at: "bottom center"
                },
                right: {
                    my: "left center",
                    at: "right center"
                },
                left: {
                    my: "right center",
                    at: "left center"
                },
                topNone: {
                    my: "bottom center",
                    at: "top center",
                    collision: "none"
                },
                bottomNone: {
                    my: "top center",
                    at: "bottom center",
                    collision: "none"
                },
                rightNone: {
                    my: "left center",
                    at: "right center",
                    collision: "none"
                },
                leftNone: {
                    my: "right center",
                    at: "left center",
                    collision: "none"
                }
            },
            DEFAULT_VIEWPORT_OFFSET = "10 10";
        DX.registerComponent("dxPopover", ui.dxPopup.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    target: window,
                    shading: false,
                    position: 'bottom',
                    closeOnOutsideClick: $.proxy(this._isOutsideClick, this),
                    animation: {
                        show: {
                            type: "fade",
                            from: 0,
                            to: 1
                        },
                        hide: {
                            type: "fade",
                            to: 0
                        }
                    },
                    showTitle: false,
                    width: "auto",
                    height: "auto",
                    dragEnabled: false,
                    fullScreen: false,
                    closeOnTargetScroll: true
                })
            },
            _defaultOptionsRules: function() {
                return []
            },
            _render: function() {
                this._element().addClass(POPOVER_CLASS);
                this._wrapper().addClass(POPOVER_WRAPPER_CLASS);
                this._renderArrow();
                this.callBase()
            },
            _renderArrow: function() {
                this._$arrow = $("<div>").addClass(POPOVER_ARROW_CLASS).appendTo(this._wrapper())
            },
            _setContentHeight: function(fullUpdate) {
                if (fullUpdate)
                    this.callBase()
            },
            _updateContentSize: function(containerLocation) {
                if (!this._$content)
                    return;
                var positionAt = this._position.at.split(" ")[0];
                if (containerLocation.h.oversize > 0 && (positionAt === "left" || positionAt === "right")) {
                    var newContainerWidth = this._$container.width() - containerLocation.h.oversize;
                    this._$container.width(newContainerWidth)
                }
                if (containerLocation.v.oversize > 0 && (positionAt === "top" || positionAt === "bottom")) {
                    var titleSize = this._$title ? this._$title.outerHeight() : 0,
                        newContainerHeight = this._$container.height() - containerLocation.v.oversize;
                    this._$container.height(newContainerHeight);
                    this._$content.outerHeight(newContainerHeight - titleSize)
                }
            },
            _isOutsideClick: function(e) {
                return !$(e.target).closest(this.option("target")).length
            },
            _animate: function(animation) {
                this.callBase.apply(this, arguments);
                if (animation)
                    DX.fx.animate(this._$arrow, $.extend({}, animation, {complete: $.noop}))
            },
            _stopAnimation: function() {
                this.callBase.apply(this, arguments);
                fx.stop(this._$arrow)
            },
            _renderTitle: function() {
                this._wrapper().toggleClass(POPOVER_WITHOUT_TITLE_CLASS, !this.option("showTitle"));
                this.callBase()
            },
            _isPopoverLargerThanTarget: function() {
                var position = this._position.at.split(" ")[0],
                    $target = $(this._position.of),
                    popoverSize,
                    targetSize;
                switch (position) {
                    case"top":
                    case"bottom":
                        popoverSize = this._$container.width();
                        targetSize = $target.outerWidth() + this._$arrow.width();
                        break;
                    case"left":
                    case"right":
                        popoverSize = this._$container.height();
                        targetSize = $target.outerHeight() + this._$arrow.height();
                        break
                }
                return popoverSize > targetSize / 2
            },
            _renderPosition: function() {
                this._normalizePosition();
                this._setContentHeight(true);
                this._togglePositionClass("dx-position-" + this._positionAlias);
                DX.translator.move(this._$arrow, {
                    left: 0,
                    top: 0
                });
                DX.translator.move(this._$container, {
                    left: 0,
                    top: 0
                });
                var contentPosition = $.extend({}, this._position),
                    $target = $(this.option("target"));
                var containerPosition = $.extend({}, contentPosition, {offset: this._$arrow.width() + " " + this._$arrow.height()}),
                    containerLocation = DX.calculatePosition(this._$container, containerPosition),
                    isFlippedByVertical = containerLocation.v.flip,
                    isFlippedByHorizontal = containerLocation.h.flip;
                this._updateContentSize(containerLocation);
                if (this._position.collision === "flip")
                    contentPosition.collision = "fit";
                var positionClass = "dx-position-" + (isFlippedByVertical || isFlippedByHorizontal ? POSITION_FLIP_MAP[this._positionAlias] : this._positionAlias);
                this._togglePositionClass(positionClass);
                if (isFlippedByVertical || isFlippedByHorizontal)
                    $.extend(contentPosition, {
                        my: contentPosition.at,
                        at: contentPosition.my
                    });
                contentPosition.offset = this._updateContentOffset(isFlippedByVertical, isFlippedByHorizontal, contentPosition.offset);
                DX.position(this._$container, contentPosition);
                var isPopoverLarger = this._isPopoverLargerThanTarget(),
                    contentPositionMy = contentPosition.my.split(" ")[0],
                    contentPositionAt = contentPosition.at.split(" ")[0];
                var arrowPosition;
                if (isPopoverLarger)
                    arrowPosition = {
                        my: contentPositionMy,
                        at: contentPositionAt,
                        of: $target
                    };
                else {
                    var arrowPosition = contentPositionAt;
                    arrowPosition = {
                        my: contentPositionAt,
                        at: contentPositionMy,
                        of: this._$container,
                        offset: this._updateArrowOffset(arrowPosition)
                    }
                }
                arrowPosition.my += " center";
                arrowPosition.at += " center";
                DX.position(this._$arrow, arrowPosition)
            },
            _renderShadingPosition: function() {
                if (this.option("shading"))
                    this._$wrapper.css({
                        top: 0,
                        left: 0
                    })
            },
            _renderShadingDimensions: function() {
                if (this.option("shading"))
                    this._$wrapper.css({
                        width: "100%",
                        height: "100%"
                    })
            },
            _togglePositionClass: function(positionClass) {
                this._$wrapper.removeClass("dx-position-left dx-position-right dx-position-top dx-position-bottom");
                this._$wrapper.addClass(positionClass)
            },
            _normalizePosition: function() {
                var position = this.option("position");
                if (DX.utils.isString(position))
                    position = $.extend({}, POSITION_ALIASES[position]);
                if (!position.of)
                    position.of = this.option("target");
                if (!position.collision)
                    position.collision = "flip";
                if (!position.viewportOffset)
                    position.viewportOffset = DEFAULT_VIEWPORT_OFFSET;
                this._positionAlias = position.at.split(" ")[0];
                this._position = position
            },
            _getOffsetObject: function(offset) {
                var result = DX.utils.stringPairToObject(offset);
                return {
                        h: result.x,
                        v: result.y
                    }
            },
            _updateContentOffset: function(isFlippedByVertical, isFlippedByHorizontal, offsetString) {
                var position = this._positionAlias,
                    offset = this._getOffsetObject(offsetString);
                var isTopPosition = position === "top" && !isFlippedByVertical || position === "bottom" && isFlippedByVertical,
                    isBottomPosition = position === "bottom" && !isFlippedByVertical || position === "top" && isFlippedByVertical,
                    isLeftPosition = position === "left" && !isFlippedByHorizontal || position === "right" && isFlippedByHorizontal,
                    isRightPosition = position === "right" && !isFlippedByHorizontal || position === "left" && isFlippedByHorizontal;
                if (isTopPosition)
                    return offset.h + " " + (offset.v - (this._$arrow.height() - 1));
                if (isBottomPosition)
                    return offset.h + " " + (offset.v + (this._$arrow.height() - 1));
                if (isLeftPosition)
                    return offset.h - (this._$arrow.width() - 1) + " " + offset.v;
                if (isRightPosition)
                    return offset.h + (this._$arrow.width() - 1) + " " + offset.v
            },
            _updateArrowOffset: function(position) {
                switch (position) {
                    case"top":
                        return "0 -1";
                    case"bottom":
                        return "0 1";
                    case"left":
                        return "-1 0";
                    case"right":
                        return "1 0"
                }
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"showTitle":
                    case"title":
                    case"titleTemplate":
                        this.callBase.apply(this, arguments);
                        this._renderPosition();
                        break;
                    case"target":
                        this._renderPosition();
                        break;
                    case"fullScreen":
                        if (value)
                            this.option("fullScreen", false);
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        ui.dxPopover.__internals = {
            POPOVER_CLASS: POPOVER_CLASS,
            POPOVER_WRAPPER_CLASS: POPOVER_WRAPPER_CLASS,
            POPOVER_ARROW_CLASS: POPOVER_ARROW_CLASS,
            POPOVER_WITHOUT_TITLE_CLASS: POPOVER_WITHOUT_TITLE_CLASS,
            DEFAULT_VIEWPORT_OFFSET: DEFAULT_VIEWPORT_OFFSET
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.tooltip.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            TOOLTIP_CLASS = "dx-tooltip",
            TOOLTIP_WRAPPER_CLASS = TOOLTIP_CLASS + "-wrapper";
        DX.registerComponent("dxTooltip", ui.dxPopover.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    showTitle: false,
                    title: undefined,
                    titleTemplate: undefined
                })
            },
            _render: function() {
                this._element().addClass(TOOLTIP_CLASS);
                this._wrapper().addClass(TOOLTIP_WRAPPER_CLASS);
                this.callBase()
            }
        }));
        ui.dxTooltip.__internals = {
            TOOLTIP_CLASS: TOOLTIP_CLASS,
            TOOLTIP_WRAPPER_CLASS: TOOLTIP_WRAPPER_CLASS
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.slider.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            fx = DX.fx,
            utils = DX.utils,
            translator = DX.translator,
            transionEndEventName = DX.support.transitionEndEventName;
        var SLIDER_CLASS = "dx-slider",
            SLIDER_WRAPPER_CLASS = SLIDER_CLASS + "-wrapper",
            SLIDER_HANDLE_CLASS = SLIDER_CLASS + "-handle",
            SLIDER_HANDLE_SELECTOR = "." + SLIDER_HANDLE_CLASS,
            SLIDER_BAR_CLASS = SLIDER_CLASS + "-bar",
            SLIDER_RANGE_CLASS = SLIDER_CLASS + "-range",
            SLIDER_RANGE_VISIBLE_CLASS = SLIDER_RANGE_CLASS + "-visible",
            SLIDER_LABEL_CLASS = SLIDER_CLASS + "-label",
            SLIDER_LABEL_POSITION_CLASS_PREFIX = SLIDER_LABEL_CLASS + "-position-",
            SLIDER_TOOLTIP_CLASS = SLIDER_CLASS + "-tooltip",
            SLIDER_TOOLTIP_POSITION_CLASS_PREFIX = SLIDER_TOOLTIP_CLASS + "-position-",
            SLIDER_TOOLTIP_ON_HOVER_ENABLED = SLIDER_TOOLTIP_CLASS + "-on-hover-enabled";
        DX.registerComponent("dxSliderHandle", ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    activeStateEnabled: false,
                    value: 50,
                    tooltipEnabled: false,
                    tooltipFormat: function(v) {
                        return v
                    },
                    tooltipPosition: "top",
                    tooltipShowMode: "onHover",
                    tooltipFitIn: null
                })
            },
            _render: function() {
                this.callBase();
                this._element().addClass(SLIDER_HANDLE_CLASS);
                this._renderTooltip()
            },
            _renderTooltip: function() {
                if (this.option("tooltipEnabled")) {
                    if (!this._$tooltip) {
                        this._$tooltip = $("<div>").appendTo(this._element()).dxTooltip({
                            visible: true,
                            height: undefined,
                            target: this._element(),
                            closeOnOutsideClick: false,
                            targetContainer: this._element(),
                            hideTopOverlayHandler: null
                        });
                        this._tooltip = this._$tooltip.dxTooltip("instance")
                    }
                    this._renderTooltipPosition();
                    this._renderTooltipShowMode();
                    this._renderValue()
                }
                else
                    this._removeTooltip()
            },
            _visibilityChanged: function() {
                this._dimensionChanged()
            },
            _dimensionChanged: function() {
                this._repaintTooltip()
            },
            _removeTooltip: function() {
                if (!this._$tooltip)
                    return;
                this._$tooltip.remove();
                delete this._$tooltip;
                delete this._tooltip
            },
            _renderTooltipPosition: function() {
                if (!this._tooltip)
                    return;
                var position = this.option("tooltipPosition");
                if ($.type(position) === "string")
                    position = position + "None";
                this._tooltip.option("position", position)
            },
            _repaintTooltip: function() {
                if (this._tooltip)
                    this._tooltip.repaint()
            },
            _renderValue: function() {
                if (!this._tooltip)
                    return;
                var format = this.option("tooltipFormat"),
                    value = format(this.option("value"));
                this._tooltip.content().html(value);
                this._fitTooltipPosition()
            },
            _renderTooltipShowMode: function() {
                this._element().toggleClass("dx-slider-tooltip-on-hover", /^onhover$/i.test(this.option("tooltipShowMode")))
            },
            _fitTooltipPosition: function() {
                if (!this._$tooltip)
                    return;
                var $tooltipContent = this._tooltip.content().parent(),
                    tooltipWidth = $tooltipContent.outerWidth(),
                    $boundElement = this.option("tooltipFitIn"),
                    boundElementWidth = $boundElement.outerWidth(),
                    boundElementLeft = $boundElement.offset().left,
                    boundElementRight = boundElementLeft + boundElementWidth,
                    $element = this._element(),
                    elementWidth = $element.outerWidth(),
                    elementLeft = $element.offset().left,
                    elementRight = elementLeft + elementWidth,
                    idealOffset = Math.round(elementWidth / 2 - tooltipWidth / 2),
                    minOffset = Math.ceil(boundElementLeft - elementLeft),
                    maxOffset = Math.floor(boundElementRight - elementRight) + idealOffset * 2,
                    newOffset = Math.min(Math.max(minOffset, idealOffset), maxOffset);
                translator.move($tooltipContent, {left: newOffset})
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"tooltipFormat":
                        this._renderValue();
                        break;
                    case"value":
                        this._renderValue();
                        break;
                    case"tooltipEnabled":
                        this._renderTooltip();
                        break;
                    case"tooltipPosition":
                        this._renderTooltipPosition();
                        break;
                    case"tooltipShowMode":
                        this._renderTooltipShowMode();
                        break;
                    case"tooltipFitIn":
                        this._fitTooltipPosition();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            fitTooltipPosition: function() {
                this._fitTooltipPosition()
            },
            repaint: function() {
                this._repaintTooltip();
                this._renderTooltipPosition();
                this._fitTooltipPosition()
            }
        }));
        DX.registerComponent("dxSlider", ui.dxEditor.inherit({
            _activeStateUnit: SLIDER_HANDLE_SELECTOR,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    min: 0,
                    max: 100,
                    step: 1,
                    value: 50,
                    showRange: true,
                    tooltip: {
                        enabled: false,
                        format: function(value) {
                            return value
                        },
                        position: "top",
                        showMode: "onHover"
                    },
                    label: {
                        visible: false,
                        position: "bottom",
                        format: function(value) {
                            return value
                        }
                    }
                })
            },
            _render: function() {
                this.callBase();
                this._element().addClass(SLIDER_CLASS);
                this._renderBar();
                this._renderRange();
                this._renderWrapper();
                this._$wrapper.dxSwipeable({
                    elastic: false,
                    startAction: $.proxy(this._handleSwipeStart, this),
                    updateAction: $.proxy(this._handleSwipeUpdate, this),
                    endAction: $.proxy(this._handleSwipeEnd, this),
                    itemSizeFunc: $.proxy(this._itemWidthFunc, this)
                });
                this._renderHandle();
                this._renderValue();
                this._renderLabels();
                this._renderStartHandler()
            },
            _visibilityChanged: function() {
                this.repaint()
            },
            _renderWrapper: function() {
                this._$wrapper = $("<div>").addClass(SLIDER_WRAPPER_CLASS).append(this._$bar).appendTo(this._element())
            },
            _renderBar: function() {
                this._$bar = $("<div>").addClass(SLIDER_BAR_CLASS);
                this._$bar.off(transionEndEventName + "." + this.NAME).on(transionEndEventName, $.proxy(this._fitHandleTooltipPosition, this))
            },
            _renderRange: function() {
                this._$selectedRange = $("<div>").addClass(SLIDER_RANGE_CLASS).appendTo(this._$bar);
                this._renderRangeVisibility()
            },
            _renderRangeVisibility: function() {
                this._$selectedRange.toggleClass(SLIDER_RANGE_VISIBLE_CLASS, Boolean(this.option("showRange")))
            },
            _renderHandle: function() {
                this._$handle = this._renderHandleImpl(this.option("value"), this._$handle)
            },
            _renderHandleImpl: function(value, $element) {
                var $handle = $element || $("<div>").appendTo(this._$selectedRange),
                    format = this._normalizeFormat(this.option("tooltip.format")),
                    tooltipEnabled = this.option("tooltip.enabled"),
                    tooltipPosition = this.option("tooltip.position");
                this._element().toggleClass(SLIDER_TOOLTIP_ON_HOVER_ENABLED, tooltipEnabled && DX.devices.real().platform !== "ios").toggleClass(SLIDER_TOOLTIP_POSITION_CLASS_PREFIX + "bottom", tooltipEnabled && tooltipPosition === "bottom").toggleClass(SLIDER_TOOLTIP_POSITION_CLASS_PREFIX + "top", tooltipEnabled && tooltipPosition === "top");
                return $handle.dxSliderHandle({
                        value: value,
                        tooltipEnabled: tooltipEnabled,
                        tooltipPosition: tooltipPosition,
                        tooltipFormat: format,
                        tooltipShowMode: this.option("tooltip.showMode"),
                        tooltipFitIn: this._element()
                    })
            },
            _renderLabels: function() {
                this._element().removeClass(SLIDER_LABEL_POSITION_CLASS_PREFIX + "bottom").removeClass(SLIDER_LABEL_POSITION_CLASS_PREFIX + "top");
                if (this.option("label.visible")) {
                    var min = this.option("min"),
                        max = this.option("max"),
                        position = this.option("label.position"),
                        format = this._normalizeFormat(this.option("label.format"));
                    if (!this._$minLabel)
                        this._$minLabel = $("<div>").addClass(SLIDER_LABEL_CLASS).appendTo(this._$wrapper);
                    this._$minLabel.html(format(min));
                    if (!this._$maxLabel)
                        this._$maxLabel = $("<div>").addClass(SLIDER_LABEL_CLASS).appendTo(this._$wrapper);
                    this._$maxLabel.html(format(max));
                    this._element().addClass(SLIDER_LABEL_POSITION_CLASS_PREFIX + position)
                }
                else {
                    if (this._$minLabel) {
                        this._$minLabel.remove();
                        delete this._$minLabel
                    }
                    if (this._$maxLabel) {
                        this._$maxLabel.remove();
                        delete this._$maxLabel
                    }
                }
            },
            _normalizeFormat: function(formatSource) {
                var format = formatSource;
                if (typeof formatSource === "string")
                    format = function(value) {
                        return Globalize.format(value, formatSource)
                    };
                else if ($.isFunction(formatSource))
                    format = $.proxy(format, this);
                else
                    format = function(value) {
                        return value
                    };
                return format
            },
            _renderDimensions: function() {
                this.callBase();
                if (this._$bar) {
                    var barMarginWidth = this._$bar.outerWidth(true) - this._$bar.outerWidth();
                    this._$bar.width(this.option("width") - barMarginWidth)
                }
            },
            _renderStartHandler: function() {
                var eventName = events.addNamespace("dxpointerdown", this.NAME),
                    startAction = this._createAction($.proxy(this._handleStart, this), {excludeValidators: ["gesture"]});
                this._element().off(eventName).on(eventName, function(e) {
                    e.preventDefault();
                    startAction({jQueryEvent: e})
                })
            },
            _itemWidthFunc: function() {
                return this._element().width() / this._swipePixelRatio()
            },
            _handleSwipeStart: function(e) {
                var rtlEnabled = this.option("rtlEnabled"),
                    startOffset,
                    endOffset;
                this._startOffset = this._currentRatio;
                startOffset = this._startOffset * this._swipePixelRatio();
                endOffset = (1 - this._startOffset) * this._swipePixelRatio();
                e.jQueryEvent.maxLeftOffset = rtlEnabled ? endOffset : startOffset;
                e.jQueryEvent.maxRightOffset = rtlEnabled ? startOffset : endOffset;
                this._swipeHandled = true
            },
            _handleSwipeEnd: function(e) {
                var offsetDirection = this.option("rtlEnabled") ? -1 : 1;
                delete this._swipeHandled;
                this._changeValueOnSwipe(this._startOffset + offsetDirection * e.jQueryEvent.targetOffset / this._swipePixelRatio());
                delete this._startOffset;
                this._renderValue()
            },
            _activeHandle: function() {
                return this._$handle
            },
            _handleSwipeUpdate: function(e) {
                this._valueChangeEventInstance = e;
                this._updateHandlePosition(e)
            },
            _updateHandlePosition: function(e) {
                var offsetDirection = this.option("rtlEnabled") ? -1 : 1;
                var newRatio = this._startOffset + offsetDirection * e.jQueryEvent.offset / this._swipePixelRatio();
                this._$selectedRange.width(newRatio * 100 + "%");
                this._changeValueOnSwipe(newRatio)
            },
            _swipePixelRatio: function() {
                var min = this.option("min"),
                    max = this.option("max"),
                    step = this._valueStep();
                return (max - min) / step
            },
            _valueStep: function() {
                var step = this.option("step");
                if (!step || isNaN(step))
                    step = 1;
                step = parseFloat(step.toFixed(5));
                if (step === 0)
                    step = 0.00001;
                return step
            },
            _changeValueOnSwipe: function(ratio) {
                var min = this.option("min"),
                    max = this.option("max"),
                    step = this._valueStep(),
                    newChange = ratio * (max - min),
                    newValue = min + newChange;
                if (step < 0)
                    return;
                if (newValue === max || newValue === min)
                    this.option("value", newValue);
                else {
                    var stepChunks = (step + "").split('.'),
                        exponent = stepChunks.length > 1 ? stepChunks[1].length : exponent;
                    newValue = Number((Math.round(newChange / step) * step + min).toFixed(exponent));
                    this.option("value", Math.max(Math.min(newValue, max), min))
                }
            },
            _handleStart: function(args) {
                var e = args.jQueryEvent;
                if (events.needSkipEvent(e))
                    return;
                this._feedbackOn(this._activeHandle(), true);
                this._currentRatio = (ui.events.eventData(e).x - this._$bar.offset().left) / this._$bar.width();
                if (this.option("rtlEnabled"))
                    this._currentRatio = 1 - this._currentRatio;
                this._valueChangeEventInstance = e;
                this._changeValueOnSwipe(this._currentRatio)
            },
            _renderValue: function() {
                var val = this.option("value"),
                    min = this.option("min"),
                    max = this.option("max");
                if (min > max)
                    return;
                if (val < min) {
                    this.option("value", min);
                    this._currentRatio = 0;
                    return
                }
                if (val > max) {
                    this.option("value", max);
                    this._currentRatio = 1;
                    return
                }
                var ratio = min === max ? 0 : (val - min) / (max - min);
                this._animateRange({width: ratio * 100 + "%"});
                this._currentRatio = ratio;
                this._activeHandle().dxSliderHandle("option", "value", this.option("value"))
            },
            _animateRange: function(configTo) {
                fx.stop(this._$selectedRange);
                if (!this._swipeHandled)
                    fx.animate(this._$selectedRange, {
                        type: "custom",
                        duration: 100,
                        to: configTo,
                        complete: $.proxy(this._fitHandleTooltipPosition, this)
                    })
            },
            _fitHandleTooltipPosition: function() {
                if (this._activeHandle())
                    this._activeHandle().dxSliderHandle("fitTooltipPosition")
            },
            _repaintHandle: function() {
                this._$handle.dxSliderHandle("repaint")
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"visible":
                        this.callBase.apply(this, arguments);
                        this._renderHandle();
                        this._repaintHandle();
                        break;
                    case"min":
                    case"max":
                        this._renderValue();
                        this._renderLabels();
                        break;
                    case"step":
                        this._renderValue();
                        break;
                    case"value":
                        this._renderValue();
                        this.callBase.apply(this, arguments);
                        break;
                    case"showRange":
                        this._renderRangeVisibility();
                        break;
                    case"tooltip":
                        this._renderHandle();
                        break;
                    case"label":
                        this._renderLabels();
                        break;
                    case"rtlEnabled":
                        this._toggleRTLDirection();
                        this._renderValue();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _dispose: function() {
                fx.stop(this._$selectedRange);
                this.callBase.apply(this, arguments)
            },
            _refresh: function() {
                this._renderDimensions();
                this._renderValue();
                this._renderHandle()
            },
            _feedbackOff: function(immediate, isGestureStart) {
                if (immediate && !isGestureStart)
                    return;
                this.callBase.apply(this, arguments)
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.rangeSlider.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events;
        var SLIDER_HANDLE_CLASS = "dx-slider-handle",
            RANGE_SLIDER_CLASS = "dx-range-slider",
            RANGE_SLIDER_START_HANDLE_CLASS = RANGE_SLIDER_CLASS + "-start-handle";
        DX.registerComponent("dxRangeSlider", ui.dxSlider.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    start: 40,
                    end: 60,
                    value: 50
                })
            },
            _render: function() {
                this.callBase();
                this._element().addClass(RANGE_SLIDER_CLASS)
            },
            _renderHandle: function() {
                this._$handleStart = this._renderHandleImpl(this.option("start"), this._$handleStart).addClass(RANGE_SLIDER_START_HANDLE_CLASS);
                this._$handleEnd = this._renderHandleImpl(this.option("end"), this._$handleEnd)
            },
            _handleStart: function(args) {
                var e = args.jQueryEvent,
                    $range = this._$selectedRange,
                    rangeWidth = $range.width(),
                    eventOffsetX = events.eventData(e).x - this._$bar.offset().left,
                    startHandleX = $range.position().left,
                    endHandleX = $range.position().left + rangeWidth,
                    rtlEnabled = this.option("rtlEnabled"),
                    startHandleIsClosest = (rtlEnabled ? -1 : 1) * ((startHandleX + endHandleX) / 2 - eventOffsetX) > 0;
                this._feedbackOff(true, true);
                this._capturedHandle = startHandleIsClosest ? this._$handleStart : this._$handleEnd;
                this.callBase(args)
            },
            _activeHandle: function() {
                return this._capturedHandle
            },
            _updateHandlePosition: function(e) {
                var rtlEnabled = this.option("rtlEnabled"),
                    offsetDirection = rtlEnabled ? -1 : 1,
                    max = this.option("max"),
                    min = this.option("min");
                var newRatio = this._startOffset + offsetDirection * e.jQueryEvent.offset / this._swipePixelRatio(),
                    newRatio = newRatio.toPrecision(12),
                    newValue = newRatio * (max - min) + min;
                this._updateSelectedRangePosition(newRatio, newRatio);
                this._changeValueOnSwipe(newRatio);
                var startValue = this.option("start"),
                    endValue = this.option("end"),
                    $nextHandle;
                if (startValue === endValue) {
                    if (newValue < startValue)
                        $nextHandle = this._$handleStart;
                    else
                        $nextHandle = this._$handleEnd;
                    if ($nextHandle && $nextHandle !== this._capturedHandle) {
                        this._updateSelectedRangePosition((startValue - min) / (max - min), (endValue - min) / (max - min));
                        this._feedbackOff(true, true);
                        this._feedbackOn($nextHandle, true);
                        this._capturedHandle = $nextHandle
                    }
                    this._updateSelectedRangePosition(newRatio, newRatio);
                    this._changeValueOnSwipe(newRatio)
                }
            },
            _updateSelectedRangePosition: function(leftRatio, rightRatio) {
                var rtlEnabled = this.option("rtlEnabled"),
                    moveRight = this._capturedHandle === this._$handleStart && rtlEnabled || this._capturedHandle === this._$handleEnd && !rtlEnabled;
                var prop = moveRight ? "right" : "left";
                if (rtlEnabled ^ moveRight)
                    this._$selectedRange.css(prop, 100 - rightRatio * 100 + "%");
                else
                    this._$selectedRange.css(prop, leftRatio * 100 + "%")
            },
            _changeValueOnSwipe: function(ratio) {
                this._suppressValueChangeAction();
                this.callBase(ratio);
                this._resumeValueChangeAction();
                var option = this._capturedHandle === this._$handleStart ? "start" : "end",
                    start = this.option("start"),
                    end = this.option("end"),
                    newValue = this.option("value"),
                    max = this.option("max"),
                    min = this.option("min");
                if (start > max) {
                    start = max;
                    this.option("start", max)
                }
                if (start < min) {
                    start = min;
                    this.option("start", min)
                }
                if (end > max) {
                    end = max;
                    this.option("end", max)
                }
                if (newValue > end && option === "start")
                    newValue = end;
                if (newValue < start && option === "end")
                    newValue = start;
                this.option(option, newValue)
            },
            _renderValue: function() {
                var valStart = this.option("start"),
                    valEnd = this.option("end"),
                    min = this.option("min"),
                    max = this.option("max"),
                    rtlEnabled = this.option("rtlEnabled");
                valStart = Math.max(min, Math.min(valStart, max));
                valEnd = Math.max(valStart, Math.min(valEnd, max));
                var ratio1 = max === min ? 0 : (valStart - min) / (max - min),
                    ratio2 = max === min ? 0 : (valEnd - min) / (max - min);
                var startOffset = parseFloat((ratio1 * 100).toPrecision(12)) + "%",
                    endOffset = parseFloat(((1 - ratio2) * 100).toPrecision(12)) + "%";
                this._animateRange({
                    right: rtlEnabled ? startOffset : endOffset,
                    left: rtlEnabled ? endOffset : startOffset
                });
                this._renderHandle()
            },
            _repaintHandle: function() {
                this._$handleStart.dxSliderHandle("repaint");
                this._$handleEnd.dxSliderHandle("repaint")
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"start":
                    case"end":
                        this._renderValue();
                        this._createActionByOption("valueChangeAction")({
                            start: this.option("start"),
                            end: this.option("end")
                        });
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.calendar.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            fx = DX.fx,
            support = DX.support,
            events = ui.events,
            utils = DX.utils,
            CALENDAR_CLASS = "dx-calendar",
            CALENDAR_BODY_CLASS = "dx-calendar-body",
            CALENDAR_NAVIGATOR_CLASS = "dx-calendar-navigator",
            CALENDAR_OTHER_MONTH_CLASS = "dx-calendar-other-month",
            CALENDAR_EMPTY_CELL_CLASS = "dx-calendar-empty-cell",
            CALENDAR_DISABLED_NAVIGATOR_LINK_CLASS = "dx-calendar-disabled-navigator-link",
            CALENDAR_TODAY_CLASS = "dx-calendar-today",
            CALENDAR_SELECTED_DATE_CLASS = "dx-calendar-selected-date",
            CALENDAR_CONTOURED_DATE_CLASS = "dx-calendar-contoured-date",
            CALENDAR_NAVIGATOR_PREVIOUS_YEAR_CLASS = "dx-calendar-navigator-previous-year",
            CALENDAR_NAVIGATOR_PREVIOUS_MONTH_CLASS = "dx-calendar-navigator-previous-month",
            CALENDAR_NAVIGATOR_NEXT_MONTH_CLASS = "dx-calendar-navigator-next-month",
            CALENDAR_NAVIGATOR_NEXT_YEAR_CLASS = "dx-calendar-navigator-next-year",
            CALENDAR_MONTHVIEW_VALUECHANGED_EVENT_NAME = "dxCalendar.MonthView.ValueChanged",
            CALENDAR_MONTHVIEW_CONTOUREDDATECHANGED_EVENT_NAME = "dxCalendar.MonthView.ContouredDateChanged",
            CALENDAR_DXCLICK_EVENT_NAME = events.addNamespace("dxclick", "dxCalendar"),
            CALENDAR_BLUR_EVENT_NAME = events.addNamespace("blur", "dxCalendar");
        var BaseView = DX.Class.inherit({
                ctor: function(options) {
                    this.date = options.date || new Date;
                    this.rtl = options.rtl
                },
                render: function(rootElement) {
                    this.rootElement = rootElement;
                    this.renderCore()
                },
                renderCore: $.noop
            }),
            views = {MonthView: BaseView.inherit({
                    ctor: function(options) {
                        options = options || {};
                        this.callBase(options);
                        this.firstDayOfWeek = options.firstDayOfWeek || 0;
                        if (options.keyDownProcessor && !options.disabled)
                            this.keyDownProcessor = options.keyDownProcessor.reinitialize(this.keyDownHandler, this);
                        if (options.contouredDate)
                            this.contouredDate = this.calculateContouredDate(options.contouredDate, options.value);
                        this.weeks = 6;
                        this.days = 7;
                        this.initialValue = options.value;
                        this.keyboardNavigationUsed = options.keyboardNavigationUsed;
                        this.min = options.min;
                        this.max = options.max;
                        this.disabled = options.disabled
                    },
                    dispose: function() {
                        if (this.keyDownProcessor)
                            this.keyDownProcessor.dispose();
                        $(this.table).remove()
                    },
                    detachKeyDownProcessor: function() {
                        var processor = this.keyDownProcessor;
                        this.keyDownProcessor = undefined;
                        return processor
                    },
                    renderCore: function() {
                        var that = this;
                        this.table = document.createElement("table");
                        this.renderHeader();
                        this.renderBody();
                        this.setValue(this.initialValue);
                        if (!this.disabled)
                            $(this.table).off(CALENDAR_DXCLICK_EVENT_NAME).on(CALENDAR_DXCLICK_EVENT_NAME, "td", function(e) {
                                that.cellClickHandler(e)
                            });
                        if (!this.keyDownProcessor && !this.disabled) {
                            this.table.setAttribute("tabindex", -1);
                            this.keyDownProcessor = new ui.HierarchicalKeyDownProcessor({
                                element: this.table,
                                handler: this.keyDownHandler,
                                context: this
                            })
                        }
                        this.setContouredDate(this.contouredDate, true);
                        this.rootElement.appendChild(this.table)
                    },
                    renderHeader: function() {
                        var that = this,
                            header = this.table.createTHead(),
                            headerRow = header.insertRow(-1),
                            th,
                            caption;
                        this.iterateDays(function(i) {
                            th = document.createElement("th");
                            caption = document.createTextNode(that.getDayCaption(that.firstDayOfWeek + i));
                            th.appendChild(caption);
                            headerRow.appendChild(th)
                        })
                    },
                    renderBody: function() {
                        var that = this,
                            tbody = document.createElement("tbody"),
                            i,
                            row,
                            cell,
                            cellDate,
                            caption,
                            today = new Date;
                        this.table.appendChild(tbody);
                        for (i = 0; i < this.weeks; ++i) {
                            row = tbody.insertRow(-1);
                            this.iterateDays(function(j) {
                                cell = row.insertCell(-1);
                                cellDate = that.getDate(i, j);
                                if (utils.sameMonthAndYear(cellDate, today) && cellDate.getDate() === today.getDate())
                                    cell.setAttribute("class", CALENDAR_TODAY_CLASS);
                                if (!utils.dateInRange(cellDate, that.min, that.max))
                                    cell.setAttribute("class", CALENDAR_EMPTY_CELL_CLASS);
                                else if (cellDate.getMonth() !== that.date.getMonth())
                                    cell.setAttribute("class", CALENDAR_OTHER_MONTH_CLASS);
                                cell.setAttribute("data-value", that.getShortDate(cellDate));
                                caption = document.createTextNode(cellDate.getDate());
                                cell.appendChild(caption)
                            })
                        }
                    },
                    getDayCaption: function(day) {
                        day = day < 7 ? day : Math.abs(day % 7);
                        return Globalize.culture().calendar.days.namesShort[day]
                    },
                    getNavigatorCaption: function() {
                        var navigatorMonth = Globalize.culture().calendar.months.names[this.date.getMonth()],
                            navigatorYear = this.date.getFullYear();
                        return this.rtl ? navigatorYear + " " + navigatorMonth : navigatorMonth + " " + navigatorYear
                    },
                    getDate: function(week, day) {
                        var firstDay = utils.getFirstMonthDate(this.date),
                            firstMonthDayPosition = firstDay.getDay() - this.firstDayOfWeek,
                            firstWeekDay = 7 * week - firstMonthDayPosition;
                        firstWeekDay = firstMonthDayPosition < 0 ? firstWeekDay - 7 : firstWeekDay;
                        firstDay.setDate(firstDay.getDate() + firstWeekDay + day);
                        return firstDay
                    },
                    getShortDate: function(date) {
                        return date.getFullYear() + "/" + date.getMonth() + "/" + date.getDate()
                    },
                    getDateFromShortDate: function(shortDate) {
                        var dateParts = shortDate.split("/");
                        return new Date(dateParts[0], dateParts[1], dateParts[2])
                    },
                    iterateDays: function(delegate) {
                        var i = this.rtl ? this.days - 1 : 0;
                        while (this.rtl ? i >= 0 : i < this.days) {
                            delegate(i);
                            this.rtl ? --i : ++i
                        }
                    },
                    cellClickHandler: function(e) {
                        var cellDate = this.getDateFromShortDate(e.target.getAttribute("data-value"));
                        if (utils.dateInRange(cellDate, this.min, this.max)) {
                            if (this.table.getAttribute("tabindex") && this.table !== document.activeElement)
                                $(this.table).focus();
                            this.setValue(cellDate, e.target)
                        }
                    },
                    keyDownHandler: function(options) {
                        var dayDifference,
                            contouredDate;
                        switch (options.key) {
                            case"leftArrow":
                                this.keyboardNavigationUsed = true;
                                dayDifference = this.rtl ? 1 : -1;
                                break;
                            case"rightArrow":
                                this.keyboardNavigationUsed = true;
                                dayDifference = this.rtl ? -1 : 1;
                                break;
                            case"upArrow":
                                this.keyboardNavigationUsed = true;
                                dayDifference = -7;
                                break;
                            case"downArrow":
                                this.keyboardNavigationUsed = true;
                                dayDifference = 7;
                                break;
                            case"enter":
                                this.keyboardNavigationUsed = true;
                                if (this.contouredDate)
                                    this.setValue(this.contouredDate, this.tryGetCell(this.contouredDate));
                                return;
                            default:
                                return
                        }
                        options.originalEvent.stopPropagation();
                        options.originalEvent.preventDefault();
                        contouredDate = this.calculateContouredDate(this.contouredDate, this.value);
                        this.setContouredDate(new Date(contouredDate.getFullYear(), contouredDate.getMonth(), contouredDate.getDate() + dayDifference))
                    },
                    calculateContouredDate: function(contouredDate, value) {
                        var calculatedContouredDate;
                        if (utils.sameMonthAndYear(contouredDate, this.date))
                            calculatedContouredDate = contouredDate;
                        if (!calculatedContouredDate && utils.sameMonthAndYear(value, this.date))
                            calculatedContouredDate = value;
                        return calculatedContouredDate || utils.getFirstMonthDate(this.date)
                    },
                    setContouredDate: function(date, suppressChangedEvent) {
                        if (this.keyboardNavigationUsed) {
                            date = utils.normalizeDate(date, this.min, this.max);
                            var dateCell;
                            if (this.contouredDate) {
                                dateCell = this.tryGetCell(this.contouredDate);
                                if (dateCell)
                                    dateCell.removeClass(CALENDAR_CONTOURED_DATE_CLASS)
                            }
                            this.contouredDate = date;
                            dateCell = this.tryGetCell(this.contouredDate);
                            if (dateCell)
                                dateCell.addClass(CALENDAR_CONTOURED_DATE_CLASS);
                            if (!suppressChangedEvent)
                                $(this.table).trigger(CALENDAR_MONTHVIEW_CONTOUREDDATECHANGED_EVENT_NAME, date)
                        }
                    },
                    setValue: function(value, cell) {
                        if (this.value !== value) {
                            this.value = value;
                            this.onValueChanged(value, cell)
                        }
                    },
                    tryGetCell: function(date) {
                        var foundCell = date ? $(this.table).find("td[data-value='" + this.getShortDate(date) + "']") : [];
                        return foundCell.length > 0 ? foundCell : undefined
                    },
                    onValueChanged: function(newValue, selectedCell) {
                        $(this.selectedCell).removeClass(CALENDAR_SELECTED_DATE_CLASS);
                        this.selectedCell = selectedCell || this.tryGetCell(newValue);
                        $(this.selectedCell).addClass(CALENDAR_SELECTED_DATE_CLASS);
                        if (selectedCell) {
                            this.setContouredDate(newValue);
                            $(this.rootElement).trigger(CALENDAR_MONTHVIEW_VALUECHANGED_EVENT_NAME, newValue)
                        }
                    }
                })};
        DX.registerComponent("dxCalendar", ui.dxEditor.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    monthViewType: views.MonthView,
                    firstDayOfWeek: 1,
                    min: undefined,
                    max: undefined
                })
            },
            _initOptions: function(options) {
                options.currentDate = utils.normalizeDate(options.currentDate || options.value || new Date, options.min, options.max);
                this.callBase(options)
            },
            _clean: function() {
                if (!this.option("keyDownProcessor") && this._keyDownProcessor)
                    this._keyDownProcessor.dispose();
                if (this._view)
                    this._view.dispose();
                this.callBase()
            },
            _refresh: function() {
                this._render()
            },
            _render: function() {
                var that = this,
                    viewKeyDownProcessor;
                this.callBase();
                this._element().addClass(CALENDAR_CLASS);
                this._initializeKeyDownProcessor();
                this._oldView = this._view;
                viewKeyDownProcessor = this._oldView ? this._oldView.detachKeyDownProcessor() : this._keyDownProcessor.attachChildProcessor();
                this._view = this._initializeMonthView(viewKeyDownProcessor);
                this._renderNavigator();
                if (!this._body) {
                    this._body = $("<div />").addClass(CALENDAR_BODY_CLASS);
                    this._element().append(this._body)
                }
                this._renderMonthView();
                if (!this._swipeable)
                    this._swipeable = this._element().dxSwipeable({
                        elastic: false,
                        startAction: function(e) {
                            that._handleSwipeStart(e)
                        },
                        updateAction: $.noop,
                        endAction: function(e) {
                            that._handleSwipeEnd(e)
                        },
                        itemWidthFunc: function() {
                            return this._element().width()
                        }
                    }).dxSwipeable("instance")
            },
            _initializeKeyDownProcessor: function() {
                var that = this;
                this._keyDownProcessor = this._keyDownProcessor || this.option("keyDownProcessor");
                if (!this._keyDownProcessor) {
                    this._element().attr("tabindex", -1).on(CALENDAR_DXCLICK_EVENT_NAME, function() {
                        that._element().focus()
                    }).on(CALENDAR_BLUR_EVENT_NAME, function() {
                        that._view.setContouredDate(undefined)
                    });
                    this._keyDownProcessor = new ui.HierarchicalKeyDownProcessor({element: this._element()})
                }
                this._keyDownProcessor.reinitialize(this._keyDownHandler, this)
            },
            _keyDownHandler: function(options) {
                var monthDifference;
                switch (options.key) {
                    case"leftArrow":
                        if (options.ctrl)
                            monthDifference = this.option("rtlEnabled") ? 1 : -1;
                        break;
                    case"rightArrow":
                        if (options.ctrl)
                            monthDifference = this.option("rtlEnabled") ? -1 : 1;
                        break;
                    case"pageUp":
                        monthDifference = -1;
                        break;
                    case"pageDown":
                        monthDifference = 1;
                        break;
                    default:
                        break
                }
                if (monthDifference) {
                    options.originalEvent.stopPropagation();
                    options.originalEvent.preventDefault();
                    this._navigate(monthDifference)
                }
                else
                    return true
            },
            _handleSwipeStart: function(e) {
                this._swipeInProgress = true
            },
            _handleSwipeEnd: function(e) {
                if (this._swipeInProgress) {
                    this._swipeInProgress = false;
                    if (e.jQueryEvent.targetOffset !== 0)
                        this._navigate(this.option("rtlEnabled") ? e.jQueryEvent.targetOffset : -e.jQueryEvent.targetOffset)
                }
            },
            _initializeMonthView: function(keyDownProcessor) {
                var monthViewType = this.option("monthViewType");
                return new monthViewType({
                        date: this.option("currentDate"),
                        min: this.option("min"),
                        max: this.option("max"),
                        firstDayOfWeek: this.option("firstDayOfWeek"),
                        value: this.option("value"),
                        rtl: this.option("rtlEnabled"),
                        disabled: this.option("disabled") || DevExpress.designMode,
                        keyDownProcessor: keyDownProcessor,
                        contouredDate: this._oldView ? this._oldView.contouredDate : undefined,
                        keyboardNavigationUsed: this._oldView ? this._oldView.keyboardNavigationUsed : undefined
                    })
            },
            _renderNavigator: function() {
                var that = this,
                    previousYearLinkDelta = this.option("rtlEnabled") ? 12 : -12,
                    previousMonthLinkDelta = this.option("rtlEnabled") ? 1 : -1,
                    nextMonthLinkDelta = this.option("rtlEnabled") ? -1 : 1,
                    nextYearLinkDelta = this.option("rtlEnabled") ? -12 : 12;
                if (this._navigator)
                    this._navigatorCaption.html(this._view.getNavigatorCaption());
                else {
                    this._previousYearLink = $("<a href='javascript:void(0)'></a>").addClass(CALENDAR_NAVIGATOR_PREVIOUS_YEAR_CLASS);
                    this._previousMonthLink = $("<a href='javascript:void(0)'></a>").addClass(CALENDAR_NAVIGATOR_PREVIOUS_MONTH_CLASS);
                    this._navigatorCaption = $("<span />").html(this._view.getNavigatorCaption()),
                    this._nextMonthLink = $("<a href='javascript:void(0)'></a>").addClass(CALENDAR_NAVIGATOR_NEXT_MONTH_CLASS);
                    this._nextYearLink = $("<a href='javascript:void(0)'></a>").addClass(CALENDAR_NAVIGATOR_NEXT_YEAR_CLASS);
                    if (!(this.option("disabled") || DevExpress.designMode)) {
                        this._previousYearLink.off(CALENDAR_DXCLICK_EVENT_NAME).on(CALENDAR_DXCLICK_EVENT_NAME, function() {
                            that._navigate(previousYearLinkDelta)
                        });
                        this._previousMonthLink.off(CALENDAR_DXCLICK_EVENT_NAME).on(CALENDAR_DXCLICK_EVENT_NAME, function() {
                            that._navigate(previousMonthLinkDelta)
                        });
                        this._nextMonthLink.off(CALENDAR_DXCLICK_EVENT_NAME).on(CALENDAR_DXCLICK_EVENT_NAME, function() {
                            that._navigate(nextMonthLinkDelta)
                        });
                        this._nextYearLink.off(CALENDAR_DXCLICK_EVENT_NAME).on(CALENDAR_DXCLICK_EVENT_NAME, function() {
                            that._navigate(nextYearLinkDelta)
                        })
                    }
                    this._navigator = $("<div />").addClass(CALENDAR_NAVIGATOR_CLASS).append(this._previousYearLink).append(this._previousMonthLink).append(this._navigatorCaption).append(this._nextMonthLink).append(this._nextYearLink);
                    this._element().append(this._navigator)
                }
                this._applyNavigatorLinkVisibility(this._previousYearLink, previousYearLinkDelta);
                this._applyNavigatorLinkVisibility(this._previousMonthLink, previousMonthLinkDelta);
                this._applyNavigatorLinkVisibility(this._nextMonthLink, nextMonthLinkDelta);
                this._applyNavigatorLinkVisibility(this._nextYearLink, nextYearLinkDelta)
            },
            _applyNavigatorLinkVisibility: function(link, monthDifference) {
                if (this._canNavigate(monthDifference))
                    link.removeClass(CALENDAR_DISABLED_NAVIGATOR_LINK_CLASS);
                else
                    link.addClass(CALENDAR_DISABLED_NAVIGATOR_LINK_CLASS)
            },
            _renderMonthView: function() {
                var that = this,
                    transitions;
                this._view.render(this._body[0]);
                this._element().off(CALENDAR_MONTHVIEW_VALUECHANGED_EVENT_NAME).on(CALENDAR_MONTHVIEW_VALUECHANGED_EVENT_NAME, function(event, newValue) {
                    that.option("value", newValue)
                });
                this._element().off(CALENDAR_MONTHVIEW_CONTOUREDDATECHANGED_EVENT_NAME).on(CALENDAR_MONTHVIEW_CONTOUREDDATECHANGED_EVENT_NAME, function(event, date) {
                    if (date)
                        if (!utils.sameMonthAndYear(that.option("currentDate"), date))
                            that.option("currentDate", utils.getFirstMonthDate(date))
                });
                if (this._oldView) {
                    this._initalizeViewDimensions();
                    this.animating = true;
                    transitions = this._getViewChangeAnimation(this._oldView, this._view, this._viewWidth, this.option("rtlEnabled"));
                    transitions.oldView.then(transitions.newView).then($.proxy(this._stopAnimationCallback, this))
                }
            },
            _initalizeViewDimensions: function() {
                this._viewWidth = this._viewWidth || this._body.width();
                this._viewHeight = this._viewHeight || this._body.height()
            },
            _canNavigate: function(monthDifference) {
                var date = this.option("currentDate"),
                    testCurrentDate = monthDifference < 0 ? new Date(date.getFullYear(), date.getMonth() + monthDifference + 1, 0) : new Date(date.getFullYear(), date.getMonth() + monthDifference, 1);
                return utils.dateInRange(testCurrentDate, this.option("min"), this.option("max"))
            },
            _navigate: function(monthDifference) {
                if (this._canNavigate(monthDifference))
                    this.option("currentDate", new Date(this.option("currentDate").getFullYear(), this.option("currentDate").getMonth() + monthDifference, 1))
            },
            _stopAnimationCallback: function() {
                this._forceStopAnimation();
                this._oldView.dispose();
                this._oldView = undefined
            },
            _forceStopAnimation: function() {
                if (this.animating) {
                    fx.stop($(this._oldView.table), true);
                    fx.stop($(this._view.table), true);
                    this.animating = false
                }
            },
            _getViewChangeAnimation: function(oldView, newView, width, rtl) {
                var transitionProperties = this._getViewChangeAnimationProperties(oldView, newView, width, rtl);
                return {
                        oldView: fx.animate($(oldView.table), transitionProperties.oldViewAnimation),
                        newView: fx.animate($(newView.table), transitionProperties.newViewAnimation)
                    }
            },
            _getViewChangeAnimationProperties: function(oldView, newView, width, rtl) {
                var type = "slide",
                    duration = oldView.date === newView.date ? 0 : 300,
                    easing = "cubic-bezier(.40, .80, .60, 1)",
                    oldViewAnimation = {
                        type: type,
                        duration: duration,
                        easing: support.transition ? easing : undefined
                    },
                    newViewAnimation = {
                        type: type,
                        duration: duration,
                        easing: support.transition ? easing : undefined
                    };
                if (newView.date > oldView.date && !rtl || newView.date < oldView.date && rtl) {
                    oldViewAnimation.from = {left: 0};
                    oldViewAnimation.to = {left: -width};
                    newViewAnimation.from = {left: width};
                    newViewAnimation.to = {left: 0}
                }
                else {
                    oldViewAnimation.from = {left: 0};
                    oldViewAnimation.to = {left: width};
                    newViewAnimation.from = {left: -width};
                    newViewAnimation.to = {left: 0}
                }
                return {
                        oldViewAnimation: oldViewAnimation,
                        newViewAnimation: newViewAnimation
                    }
            },
            _invalidate: function() {
                this._forceStopAnimation();
                this.callBase()
            },
            _optionChanged: function(name, value, previousValue) {
                var normalizedDate;
                switch (name) {
                    case"monthViewType":
                    case"keyDownProcessor":
                        break;
                    case"currentDate":
                        this._forceStopAnimation();
                        normalizedDate = utils.normalizeDate(value, this.option("min"), this.option("max"));
                        this.option("currentDate", new Date(normalizedDate.getFullYear(), normalizedDate.getMonth(), 1));
                    case"min":
                    case"max":
                    case"firstDayOfWeek":
                    case"rtlEnabled":
                        this._invalidate();
                        break;
                    case"value":
                        if (utils.sameMonthAndYear(this._view.date, value)) {
                            normalizedDate = utils.normalizeDate(value, this.option("min"), this.option("max"));
                            this._view.setValue(normalizedDate);
                            this.option("value", normalizedDate)
                        }
                        else
                            this.option("currentDate", utils.getFirstMonthDate(value));
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        ui.dxCalendar.__internals = {
            BaseView: BaseView,
            views: views,
            CALENDAR_CLASS: CALENDAR_CLASS,
            CALENDAR_BODY_CLASS: CALENDAR_BODY_CLASS,
            CALENDAR_NAVIGATOR_CLASS: CALENDAR_NAVIGATOR_CLASS,
            CALENDAR_OTHER_MONTH_CLASS: CALENDAR_OTHER_MONTH_CLASS,
            CALENDAR_DISABLED_NAVIGATOR_LINK_CLASS: CALENDAR_DISABLED_NAVIGATOR_LINK_CLASS,
            CALENDAR_EMPTY_CELL_CLASS: CALENDAR_EMPTY_CELL_CLASS,
            CALENDAR_TODAY_CLASS: CALENDAR_TODAY_CLASS,
            CALENDAR_SELECTED_DATE_CLASS: CALENDAR_SELECTED_DATE_CLASS,
            CALENDAR_CONTOURED_DATE_CLASS: CALENDAR_CONTOURED_DATE_CLASS,
            CALENDAR_NAVIGATOR_PREVIOUS_YEAR_CLASS: CALENDAR_NAVIGATOR_PREVIOUS_YEAR_CLASS,
            CALENDAR_NAVIGATOR_PREVIOUS_MONTH_CLASS: CALENDAR_NAVIGATOR_PREVIOUS_MONTH_CLASS,
            CALENDAR_NAVIGATOR_NEXT_MONTH_CLASS: CALENDAR_NAVIGATOR_NEXT_MONTH_CLASS,
            CALENDAR_NAVIGATOR_NEXT_YEAR_CLASS: CALENDAR_NAVIGATOR_NEXT_YEAR_CLASS,
            CALENDAR_MONTHVIEW_VALUECHANGED_EVENT_NAME: CALENDAR_MONTHVIEW_VALUECHANGED_EVENT_NAME,
            CALENDAR_MONTHVIEW_CONTOUREDDATECHANGED_EVENT_NAME: CALENDAR_MONTHVIEW_CONTOUREDDATECHANGED_EVENT_NAME
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.calendarPicker.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            CALENDAR_PICKER_CLASS = "dx-calendar-picker",
            CALENDAR_PICKER_CALENDAR_CONTAINER_CLASS = CALENDAR_PICKER_CLASS + "-calendar-container",
            CALENDAR_PICKER_OVERLAY = CALENDAR_PICKER_CLASS + "-overlay",
            CALENDAR_PICKER_INPUT_WRAPPER_CLASS = CALENDAR_PICKER_CLASS + "-input-wrapper",
            CALENDAR_PICKER_INPUT_WIDER_THAN_CALENDAR_CONTAINER_CLASS = CALENDAR_PICKER_CLASS + "-input-wider-than-calendar-container",
            CALENDAR_PICKER_POSITION_CLASS_PREFIX = CALENDAR_PICKER_CLASS + "-",
            CALENDAR_PICKER_DXPOINTERUP_EVENT_NAME = events.addNamespace("dxpointerup", "dxCalendarPicker"),
            getLongestCaptionIndex = function(captionArray) {
                var longestIndex = 0,
                    longestCaptionLength = 0,
                    i;
                for (i = 0; i < captionArray.length; ++i)
                    if (captionArray[i].length > longestCaptionLength) {
                        longestIndex = i;
                        longestCaptionLength = captionArray[i].length
                    }
                return longestIndex
            },
            expandPattern = function(pattern) {
                return pattern.length === 1 ? Globalize.culture().calendar.patterns[pattern] : pattern
            },
            formatUsesMonthName = function(format) {
                return expandPattern(format).indexOf("MMMM") !== -1
            },
            formatUsesDayName = function(format) {
                return expandPattern(format).indexOf("dddd") !== -1
            },
            getLongestDate = function(format, monthNames, dayNames) {
                var longestDate = new Date(1888, formatUsesMonthName(format) ? getLongestCaptionIndex(monthNames) : 9, 28 - 7, 23, 59, 59, 999);
                if (formatUsesDayName(format))
                    longestDate.setDate(longestDate.getDate() - longestDate.getDay() + getLongestCaptionIndex(dayNames));
                return longestDate
            };
        ui.calculateMaximumDateFormatWidth = function(format, customFontStyles, rootElement) {
            if (!rootElement || $(rootElement).is(":visible")) {
                var width,
                    ieRoundingError = 2,
                    longestTextDiv = $("<div>" + Globalize.format(getLongestDate(format, Globalize.culture().calendar.months.names, Globalize.culture().calendar.days.names), format) + "</div>").css({
                        visibility: "hidden",
                        "white-space": "nowrap",
                        position: "absolute",
                        float: "left"
                    });
                if (customFontStyles)
                    longestTextDiv.css(customFontStyles);
                longestTextDiv.appendTo(rootElement ? $(rootElement) : $("body"));
                width = longestTextDiv.width() + ieRoundingError;
                longestTextDiv.remove();
                return width
            }
        };
        ui.dxCalendarPicker = ui.dxDropDownEditor.inherit({
            NAME: "dxDateBox",
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    valueChangeEvent: "keyup keydown keypress",
                    formatString: Globalize.culture().calendar.patterns["d"],
                    formatWidthCalculator: ui.calculateMaximumDateFormatWidth,
                    closeOnValueChange: true
                })
            },
            _formatWidthCalculator: function() {
                var $bearingElement = this._element().find(".dx-texteditor-input"),
                    buttonWidth = this._button.outerWidth(),
                    bearingElementPaddings = $bearingElement.innerWidth() - $bearingElement.width(),
                    formatCalculator = this.option("formatWidthCalculator"),
                    width;
                if (formatCalculator)
                    width = bearingElementPaddings + buttonWidth + formatCalculator(this.option("formatString"), {
                        "font-style": $bearingElement.css("font-style"),
                        "font-variant": $bearingElement.css("font-variant"),
                        "font-weight": $bearingElement.css("font-weight"),
                        "font-size": $bearingElement.css("font-size"),
                        "font-family": $bearingElement.css("font-family"),
                        "letter-spacing": $bearingElement.css("letter-spacing")
                    }, this._element());
                return width
            },
            _clean: function() {
                if (this._keyDownProcessor)
                    this._keyDownProcessor.dispose();
                if (this._calendarKeyDownProcessor)
                    this._calendarKeyDownProcessor.dispose();
                if (this._calendarContainer)
                    this._calendarContainer.remove();
                this.callBase()
            },
            _render: function() {
                this.callBase();
                this._element().addClass(CALENDAR_PICKER_CLASS);
                this._keyDownProcessor = new ui.HierarchicalKeyDownProcessor({
                    element: this._input(),
                    handler: this._keyDownHandler,
                    context: this
                });
                this._calendarKeyDownProcessor = this._keyDownProcessor.attachChildProcessor()
            },
            _calculateWidth: function(rawValue) {
                return this.callBase() || this._formatWidthCalculator()
            },
            _keyDownHandler: function(options) {
                switch (options.key) {
                    case"escape":
                        options.originalEvent.preventDefault();
                        this._blur();
                        return;
                    default:
                        return true
                }
            },
            _applyDropDownDirectionClasses: function(directions, calendarInnerWidth) {
                if (this._element().width() > calendarInnerWidth)
                    this._dropDown._wrapper().addClass(CALENDAR_PICKER_INPUT_WIDER_THAN_CALENDAR_CONTAINER_CLASS);
                else
                    this._dropDown._wrapper().removeClass(CALENDAR_PICKER_INPUT_WIDER_THAN_CALENDAR_CONTAINER_CLASS);
                this._cleanDirections(this._dropDown._wrapper()).addClass(directions.horizontalClass + " " + directions.verticalClass)
            },
            _cleanDirections: function(element) {
                return element.removeClass(CALENDAR_PICKER_POSITION_CLASS_PREFIX + "left " + CALENDAR_PICKER_POSITION_CLASS_PREFIX + "right " + CALENDAR_PICKER_POSITION_CLASS_PREFIX + "top " + CALENDAR_PICKER_POSITION_CLASS_PREFIX + "bottom")
            },
            _createDropDown: function() {
                var that = this,
                    horizontalAlign = this.option("rtlEnabled") ? "right" : "left",
                    verticalAlign = "bottom";
                this.callBase({
                    position: {
                        my: horizontalAlign + " " + DX.inverseAlign(verticalAlign),
                        at: horizontalAlign + " " + verticalAlign
                    },
                    positioningAction: function(options) {
                        if (that._calendarContainer)
                            that._applyDropDownDirectionClasses({
                                horizontalClass: CALENDAR_PICKER_POSITION_CLASS_PREFIX + (options.position.h.flip ? horizontalAlign : DX.inverseAlign(horizontalAlign)),
                                verticalClass: CALENDAR_PICKER_POSITION_CLASS_PREFIX + (options.position.v.flip ? DX.inverseAlign(verticalAlign) : verticalAlign)
                            }, that._calendarContainer.innerWidth())
                    }
                })
            },
            _closeOutsideDropDownHandler: function(e, ignoreContainerClicks) {
                this.callBase(e, true)
            },
            _renderDropDownContent: function() {
                var that = this;
                this._calendarContainer = $("<div />").addClass(CALENDAR_PICKER_CALENDAR_CONTAINER_CLASS);
                this._calendar = this._calendarContainer.dxCalendar($.extend(this.option("calendarOptions"), {
                    value: this.option("value"),
                    rtlEnabled: this.option("rtlEnabled"),
                    keyDownProcessor: this._calendarKeyDownProcessor,
                    min: this.option("min"),
                    max: this.option("max")
                })).dxCalendar("instance");
                this._calendarContainer.on(CALENDAR_PICKER_DXPOINTERUP_EVENT_NAME, function(e) {
                    that._calendarContainerPointerUpHandler(e)
                });
                return [this._calendarContainer]
            },
            _showDropDown: function() {
                if (!this._dropDownVisible()) {
                    var containerRendered = this._dropDownContainerRendered;
                    this.callBase();
                    if (!containerRendered) {
                        this._calendar.optionChanged.add($.proxy(this._calendarOptionChangedCallback, this));
                        this._dropDown._wrapper().addClass(CALENDAR_PICKER_OVERLAY)
                    }
                }
            },
            _calendarContainerPointerUpHandler: function(e) {
                e.dxPreventBlur = true
            },
            _calendarOptionChangedCallback: function(name, value, previousValue) {
                switch (name) {
                    case"value":
                        this.option("value", value);
                    default:
                        break
                }
            },
            _optionValuesEqual: function(name, oldValue, newValue) {
                if (name === "value" && newValue === null)
                    return false;
                return this.callBase.apply(this, arguments)
            },
            _renderValue: function(formattedValue) {
                this.callBase(Globalize.format(this.option("value"), this.option("formatString")))
            },
            _handleValueChangeEvent: function(e, formattedValue) {
                this._suppressUpdateValue();
                var date = Globalize.parseDate(this._input().val(), this.option("formatString"));
                this.callBase(e, date);
                this._resumeUpdateValue()
            },
            _blur: function() {
                this._input().blur()
            },
            _visibilityChanged: function(visible) {
                if (visible)
                    this._renderDimensions()
            },
            _optionChanged: function(name, value, previousValue) {
                var that = this,
                    normalizedDate;
                switch (name) {
                    case"min":
                    case"max":
                    case"formatString":
                    case"calendarOptions":
                        this._invalidate();
                        break;
                    case"type":
                    case"formatWidthCalculator":
                    case"closeOnValueChange":
                        break;
                    case"value":
                        if (value) {
                            normalizedDate = utils.normalizeDate(value, this.option("min"), this.option("max"));
                            this.option("value", normalizedDate);
                            if (this._calendar)
                                this._calendar.option("value", value);
                            if (this._dropDownVisible() && this.option("closeOnValueChange"))
                                setTimeout($.proxy(that._hideDropDown, that), 50)
                        }
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        });
        DX.registerComponent("dxDateBoxTypeCalendarForDebugTests", ui.dxCalendarPicker.inherit({NAME: "dxDateBoxTypeCalendarForDebugTests"}));
        ui.dxCalendarPicker.__internals = {
            getLongestCaptionIndex: getLongestCaptionIndex,
            getLongestDate: getLongestDate,
            calculateMaximumDateFormatWidth: ui.calculateMaximumDateFormatWidth,
            CALENDAR_PICKER_OVERLAY: CALENDAR_PICKER_OVERLAY,
            CALENDAR_PICKER_INPUT_WIDER_THAN_CALENDAR_CONTAINER_CLASS: CALENDAR_PICKER_INPUT_WIDER_THAN_CALENDAR_CONTAINER_CLASS,
            CALENDAR_PICKER_INPUT_WRAPPER_CLASS: CALENDAR_PICKER_INPUT_WRAPPER_CLASS,
            CALENDAR_PICKER_POSITION_CLASS_PREFIX: CALENDAR_PICKER_POSITION_CLASS_PREFIX
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.calendarPickerTimeBox.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            CALENDAR_PICKER_TIME_BOX_CLASS = "dx-calendar-picker-time-box",
            TEXTEDITOR_INPUT_WRAPPER_CLASS = "dx-texteditor-input-wrapper",
            CALENDAR_PICKER_TIME_BOX_DXCLICK_EVENT_NAME = events.addNamespace("dxclick", "dxCalendarPickerTimeBox");
        DX.registerComponent("dxCalendarPickerTimeBox", ui.dxTextEditor.inherit({
            _processingKeyPress: undefined,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    valueChangeEvent: "keyup keydown keypress",
                    formatString: Globalize.culture().calendar.patterns["t"],
                    formatWidthCalculator: ui.calculateMaximumDateFormatWidth
                })
            },
            _formatWidthCalculator: function() {
                var $element = this._element(),
                    $bearingElement = $element.find(".dx-texteditor-input"),
                    paddingWidth = $element.innerWidth() - $element.width(),
                    formatWidthCalculator = this.option("formatWidthCalculator"),
                    width;
                if (formatWidthCalculator)
                    width = paddingWidth + formatWidthCalculator(this.option("formatString"), {
                        "font-style": $bearingElement.css("font-style"),
                        "font-variant": $bearingElement.css("font-variant"),
                        "font-weight": $bearingElement.css("font-weight"),
                        "font-size": $bearingElement.css("font-size"),
                        "font-family": $bearingElement.css("font-family"),
                        "letter-spacing": $bearingElement.css("letter-spacing")
                    });
                return width
            },
            _render: function() {
                var that = this,
                    $element = this._element();
                $element.addClass(CALENDAR_PICKER_TIME_BOX_CLASS);
                this.callBase();
                $element.off(CALENDAR_PICKER_TIME_BOX_DXCLICK_EVENT_NAME).on(CALENDAR_PICKER_TIME_BOX_DXCLICK_EVENT_NAME, function() {
                    that.focus()
                });
                this._repositionIcon($element.width())
            },
            _calculateWidth: function(rawValue) {
                var width = this.callBase();
                if (!width)
                    width = this._formatWidthCalculator();
                return width
            },
            _renderValue: function(formattedValue) {
                this.callBase(Globalize.format(this.option("value"), this.option("formatString")))
            },
            _renderInput: function() {
                this.callBase();
                this._element().addClass(TEXTEDITOR_INPUT_WRAPPER_CLASS)
            },
            _repositionIcon: function(inputWidth) {
                if (this.option("rtlEnabled"))
                    return;
                var ie8 = DX.browser.msie && DX.browser.version < 9,
                    backgroundPosition = ie8 ? [this._element().css("backgroundPositionX"), this._element().css("backgroundPositionY")] : this._element().css("background-position").split(" ");
                this._iconWidth = this._iconWidth || parseInt(backgroundPosition[0], 10);
                if (ie8) {
                    this._element().css("backgroundPositionX", inputWidth + this._iconWidth + "px");
                    this._element().css("backgroundPositionY", backgroundPosition[1])
                }
                else
                    this._element().css("background-position", inputWidth + this._iconWidth + "px " + backgroundPosition[1])
            },
            _handleValueChangeEvent: function(e, formattedValue) {
                this._suppressUpdateValue();
                var time = Globalize.parseDate(this._input().val(), this.option("formatString"));
                this.callBase(e, time);
                this._resumeUpdateValue()
            },
            _optionChanged: function(name, value, previousValue) {
                switch (name) {
                    case"formatWidthCalculator":
                        break;
                    case"formatString":
                        this._invalidate();
                        break;
                    case"width":
                        this.callBase.apply(this, arguments);
                        this._repositionIcon(this._element().width());
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        ui.dxCalendarPickerTimeBox.__internals = {TEXTEDITOR_INPUT_WRAPPER_CLASS: TEXTEDITOR_INPUT_WRAPPER_CLASS}
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.dateBox.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            support = DX.support,
            devices = DX.devices,
            globalize = Globalize;
        var DATEBOX_CLASS = "dx-datebox",
            DATEPICKER_CLASS = "dx-datepicker",
            DATEPICKER_WRAPPER_CLASS = "dx-datepicker-wrapper",
            DATEPICKER_ROLLER_CONTAINER_CLASS = "dx-datepicker-rollers",
            DATEPICKER_ROLLER_CLASS = "dx-datepicker-roller",
            DATEPICKER_ROLLER_ACTIVE_CLASS = "dx-state-active",
            DATEPICKER_ROLLER_CURRENT_CLASS = "dx-datepicker-roller-current",
            DATEPICKER_ROLLER_ITEM_CLASS = "dx-datepicker-item",
            DATEPICKER_ROLLER_ITEM_SELECTED_CLASS = "dx-datepicker-item-selected",
            DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS = "dx-datepicker-item-selected-frame",
            DATEPICKER_ROLLER_BUTTON_UP_CLASS = "dx-datepicker-button-up",
            DATEPICKER_ROLLER_BUTTON_DOWN_CLASS = "dx-datepicker-button-down",
            DATEPICKER_FORMATTER_CONTAINER = "dx-datepicker-formatter-container",
            DATEPICKER_VALUE_FORMATTER = "dx-datepicker-value-formatter",
            DATEPICKER_NAME_FORMATTER = "dx-datepicker-name-formatter",
            SUPPORTED_FORMATS = ["date", "time", "datetime"],
            DEFAULT_FORMATTER = function(value) {
                return value
            },
            DATE_COMPONENT_TEXT_FORMATTER = function(value, name) {
                var $container = $("<div>").addClass(DATEPICKER_FORMATTER_CONTAINER);
                $("<span>").text(value).addClass(DATEPICKER_VALUE_FORMATTER).appendTo($container);
                $("<span>").text(name).addClass(DATEPICKER_NAME_FORMATTER).appendTo($container);
                return $container
            },
            YEAR = "year",
            MONTH = "month",
            DAY = "day",
            HOURS = "hours",
            MINUTES = "minutes",
            SECONDS = "seconds",
            MILLISECONDS = "milliseconds",
            TEN_YEARS = 1000 * 60 * 60 * 24 * 365 * 10;
        var DATE_COMPONENTS_INFO = {};
        DATE_COMPONENTS_INFO[YEAR] = {
            getter: "getFullYear",
            setter: "setFullYear",
            possibleFormats: ["yy", "yyyy"],
            formatter: DEFAULT_FORMATTER,
            startValue: undefined,
            endValue: undefined
        };
        DATE_COMPONENTS_INFO[DAY] = {
            getter: "getDate",
            setter: "setDate",
            possibleFormats: ["d", "dd"],
            formatter: function(value, showNames, date) {
                if (!showNames)
                    return value;
                var formatDate = new Date(date.getTime());
                formatDate.setDate(value);
                return DATE_COMPONENT_TEXT_FORMATTER(value, globalize.culture().calendar.days.names[formatDate.getDay()])
            },
            startValue: 1,
            endValue: undefined
        };
        DATE_COMPONENTS_INFO[MONTH] = {
            getter: "getMonth",
            setter: "setMonth",
            possibleFormats: ["M", "MM", "MMM", "MMMM"],
            formatter: function(value, showNames) {
                var monthName = globalize.culture().calendar.months.names[value];
                return showNames ? DATE_COMPONENT_TEXT_FORMATTER(value + 1, monthName) : monthName
            },
            startValue: 0,
            endValue: 11
        };
        DATE_COMPONENTS_INFO[HOURS] = {
            getter: "getHours",
            setter: "setHours",
            possibleFormats: ["H", "HH", "h", "hh"],
            formatter: function(value) {
                return globalize.format(new Date(0, 0, 0, value), "HH")
            },
            startValue: 0,
            endValue: 23
        };
        DATE_COMPONENTS_INFO[MINUTES] = {
            getter: "getMinutes",
            setter: "setMinutes",
            possibleFormats: ["m", "mm"],
            formatter: function(value) {
                return globalize.format(new Date(0, 0, 0, 0, value), "mm")
            },
            startValue: 0,
            endValue: 59
        };
        DATE_COMPONENTS_INFO[SECONDS] = {
            getter: "getSeconds",
            setter: "setSeconds",
            possibleFormats: ["s", "ss"],
            formatter: function(value) {
                return globalize.format(new Date(0, 0, 0, 0, 0, value), "ss")
            },
            startValue: 0,
            endValue: 59
        };
        DATE_COMPONENTS_INFO[MILLISECONDS] = {
            getter: "getMilliseconds",
            setter: "setMilliseconds",
            possibleFormats: ["f", "ff", "fff"],
            formatter: function(value) {
                return globalize.format(new Date(0, 0, 0, 0, 0, 0, value), "fff")
            },
            startValue: 0,
            endValue: 999
        };
        var FORMATS_INFO = {
                date: {
                    standardPattern: "yyyy-MM-dd",
                    components: [YEAR, DAY, MONTH]
                },
                time: {
                    standardPattern: "HH:mm",
                    components: [HOURS, MINUTES]
                },
                datetime: {
                    standardPattern: "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
                    components: [YEAR, DAY, MONTH, HOURS, MINUTES, SECONDS, MILLISECONDS]
                },
                "datetime-local": {
                    standardPattern: "yyyy'-'MM'-'dd'T'HH':'mm",
                    components: [YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS]
                }
            },
            FORMATS_MAP = {
                date: "d",
                time: "t",
                datetime: "S",
                "datetime-local": "f"
            };
        var toStandardDateFormat = function(date, mode, pattern) {
                pattern = pattern || FORMATS_INFO[mode].standardPattern;
                var datePattern = FORMATS_INFO[mode].standardPattern;
                return Globalize.format(date, pattern)
            };
        (function androidFormatDetection() {
            var androidFormatPattern = "yyyy'-'MM'-'dd'T'HH':'mm'Z'";
            var $input = $("<input>").attr("type", "datetime");
            $input.val(toStandardDateFormat(new Date, "datetime", androidFormatPattern));
            if (!$input.val())
                FORMATS_INFO.datetime.standardPattern = androidFormatPattern
        })();
        var fromStandardDateFormat = function(date) {
                return Globalize.parseDate(date, FORMATS_INFO["datetime"].standardPattern) || Globalize.parseDate(date, FORMATS_INFO["datetime-local"].standardPattern) || Globalize.parseDate(date, FORMATS_INFO["time"].standardPattern) || Globalize.parseDate(date, FORMATS_INFO["date"].standardPattern) || Date.parse && Date.parse(date) && new Date(Date.parse(date))
            };
        var getMaxMonthDay = function(year, month) {
                return new Date(year, month + 1, 0).getDate()
            };
        var mergeDates = function(target, source, format) {
                if (!source)
                    return undefined;
                if (isNaN(target.getTime()))
                    target = new Date(0, 0, 0, 0, 0, 0);
                var formatInfo = FORMATS_INFO[format];
                $.each(formatInfo.components, function() {
                    var componentInfo = DATE_COMPONENTS_INFO[this];
                    target[componentInfo.setter](source[componentInfo.getter]())
                });
                return target
            };
        DX.registerComponent("dxDatePickerRoller", ui.dxScrollable.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    clickableItems: false,
                    showScrollbar: false,
                    useNative: false,
                    selectedIndex: 0,
                    items: []
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: {platform: "win8"},
                            options: {clickableItems: true}
                        }, {
                            device: {platform: "generic"},
                            options: {scrollByContent: true}
                        }])
            },
            _init: function() {
                this.callBase();
                this._renderSelectedItemFrame();
                this._renderControlButtons()
            },
            _render: function() {
                this.callBase();
                $.each(this._strategy._scrollers, function(index, scroller) {
                    scroller._correctLocation = $.noop
                });
                this._element().addClass(DATEPICKER_ROLLER_CLASS);
                this._renderItems();
                this._renderSelectedValue();
                this._renderItemsClick();
                this._wrapAction("_endAction", $.proxy(this._handleEndAction, this))
            },
            _wrapAction: function(actionName, callback) {
                var strategy = this._strategy,
                    originalAction = strategy[actionName];
                strategy[actionName] = function() {
                    callback.apply(this, arguments);
                    return originalAction.apply(this, arguments)
                }
            },
            _renderItems: function() {
                var items = this.option("items") || [],
                    $items = $();
                this._$content.empty();
                $.each(items, function() {
                    $items = $items.add($("<div>").addClass(DATEPICKER_ROLLER_ITEM_CLASS).append(this))
                });
                this._$content.append($items);
                this._$items = $items;
                this.update()
            },
            _renderSelectedItemFrame: function() {
                $("<div>").addClass(DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS).appendTo(this._$container)
            },
            _renderControlButtons: function() {
                $("<div>").addClass(DATEPICKER_ROLLER_BUTTON_UP_CLASS).insertAfter(this._$container).dxButton({clickAction: $.proxy(this._handleUpButtonClick, this)});
                $("<div>").addClass(DATEPICKER_ROLLER_BUTTON_DOWN_CLASS).insertAfter(this._$container).dxButton({clickAction: $.proxy(this._handleDownButtonClick, this)})
            },
            _renderSelectedValue: function(selectedIndex) {
                if (selectedIndex === undefined)
                    selectedIndex = this.option("selectedIndex");
                selectedIndex = this._fitIndex(selectedIndex);
                var correctedPosition = this._getItemPosition(selectedIndex);
                this.option().selectedIndex = selectedIndex;
                this._moveTo({top: correctedPosition});
                this._renderActiveStateItem()
            },
            _fitIndex: function(index) {
                var items = this.option("items") || [],
                    itemCount = items.length;
                if (index >= itemCount)
                    return itemCount - 1;
                if (index < 0)
                    return 0;
                return index
            },
            _renderItemsClick: function() {
                var itemSelector = "." + DATEPICKER_ROLLER_ITEM_CLASS,
                    eventName = events.addNamespace("dxclick", this.NAME);
                this._element().off(eventName, itemSelector);
                if (this.option("clickableItems"))
                    this._element().on(eventName, itemSelector, $.proxy(this._handleItemClick, this))
            },
            _handleItemClick: function(e) {
                this._renderSelectedValue(this._itemElementIndex(this._closestItemElement(e)))
            },
            _itemElementIndex: function(itemElement) {
                return this._itemElements().index(itemElement)
            },
            _closestItemElement: function(e) {
                return e.currentTarget
            },
            _itemElements: function() {
                return this._element().find("." + DATEPICKER_ROLLER_ITEM_CLASS)
            },
            _renderActiveStateItem: function() {
                var selectedIndex = this.option("selectedIndex");
                $.each(this._$items, function(index) {
                    $(this).toggleClass(DATEPICKER_ROLLER_ITEM_SELECTED_CLASS, selectedIndex === index)
                })
            },
            _handleUpButtonClick: function() {
                this._animation = true;
                this.option("selectedIndex", this.option("selectedIndex") - 1)
            },
            _handleDownButtonClick: function() {
                this._animation = true;
                this.option("selectedIndex", this.option("selectedIndex") + 1)
            },
            _getItemPosition: function(index) {
                return Math.round(this._itemHeight() * index)
            },
            _moveTo: function(targetLocation) {
                targetLocation = this._normalizeLocation(targetLocation);
                var location = this._location(),
                    delta = {
                        x: -(location.left - targetLocation.left),
                        y: -(location.top - targetLocation.top)
                    };
                if (this._isVisible() && (delta.x || delta.y)) {
                    this._strategy._prepareDirections(true);
                    if (this._animation) {
                        DX.fx.animate(this._$content, {
                            duration: 200,
                            type: "slide",
                            to: {top: targetLocation.top}
                        });
                        delete this._animation
                    }
                    else
                        this._strategy.handleMove({delta: delta})
                }
            },
            _handleEndAction: function() {
                if (this._changedByIndex) {
                    this._changedByIndex = false;
                    this._renderSelectedValue();
                    return
                }
                var ratio = -this._location().top / this._itemHeight(),
                    selectedIndex = Math.round(ratio);
                this._animation = true;
                this._renderSelectedValue(selectedIndex)
            },
            _itemHeight: function() {
                var $item = this._$items.first(),
                    height = $item.outerHeight() + parseFloat($item.css("margin-top") || 0);
                return height
            },
            _toggleActive: function(state) {
                this._element().toggleClass(DATEPICKER_ROLLER_ACTIVE_CLASS, state)
            },
            _isVisible: function() {
                return this._$container.is(":visible")
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"selectedIndex":
                        this._renderSelectedValue();
                        this._changedByIndex = true;
                        this._strategy.update();
                        this._strategy.handleEnd({velocity: {
                                x: 0,
                                y: 0
                            }});
                        break;
                    case"items":
                        this._renderItems();
                        this._renderSelectedValue();
                        break;
                    case"clickableItems":
                        this._renderItemsClick();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        DX.registerComponent("dxDatePicker", ui.dxPopup.inherit({
            _valueOption: function() {
                return new Date(this.option("value")) == "Invalid Date" ? new Date : new Date(this.option("value"))
            },
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    minDate: new Date(1),
                    maxDate: new Date($.now() + TEN_YEARS),
                    format: "date",
                    value: new Date,
                    culture: Globalize.culture().name,
                    showNames: false,
                    cancelButton: {
                        icon: "close",
                        clickAction: $.proxy(function() {
                            this._value = this._valueOption()
                        }, this)
                    },
                    doneButton: {
                        icon: "save",
                        clickAction: $.proxy(function() {
                            this.option("value", new Date(this._value));
                            this.hide()
                        }, this)
                    }
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: {platform: "win8"},
                            options: {showNames: true}
                        }, {
                            device: {
                                platform: "win8",
                                phone: true
                            },
                            options: {fullScreen: true}
                        }, {
                            device: function(device) {
                                return device.platform !== "win8"
                            },
                            options: {
                                width: 333,
                                height: 331
                            }
                        }, {
                            device: function(device) {
                                return device.platform === "generic"
                            },
                            options: {
                                width: "auto",
                                height: "auto"
                            }
                        }])
            },
            _render: function() {
                this._value = this._valueOption();
                this.callBase();
                this._element().addClass(DATEPICKER_CLASS);
                this._wrapper().addClass(DATEPICKER_WRAPPER_CLASS)
            },
            _renderContentImpl: function() {
                this.callBase();
                this._renderRollers()
            },
            _renderRollers: function() {
                var that = this;
                if (!that._$rollersContainer)
                    that._$rollersContainer = $("<div>").appendTo(that.content()).addClass(DATEPICKER_ROLLER_CONTAINER_CLASS);
                that._$rollersContainer.empty();
                that._createRollerConfigs();
                that._rollers = {};
                $.each(that._rollerConfigs, function(name) {
                    var $roller = $("<div>").appendTo(that._$rollersContainer).addClass(DATEPICKER_ROLLER_CLASS + "-" + that._rollerConfigs[name].type).dxDatePickerRoller({
                            items: that._rollerConfigs[name].displayItems,
                            selectedIndex: that._rollerConfigs[name].selectedIndex,
                            showScrollbar: false,
                            startAction: function(e) {
                                var roller = e.component;
                                roller._toggleActive(true);
                                that._setActiveRoller(that._rollerConfigs[name], roller.option("selectedIndex"))
                            },
                            endAction: function(e) {
                                var roller = e.component;
                                that._setRollerState(that._rollerConfigs[name], roller.option("selectedIndex"));
                                roller._toggleActive(false)
                            }
                        });
                    that._rollers[that._rollerConfigs[name].type] = $roller.dxDatePickerRoller("instance")
                })
            },
            _setActiveRoller: function(currentRoller) {
                var activeRoller = this._rollers[currentRoller.type];
                $.each(this._rollers, function() {
                    this._$element.toggleClass(DATEPICKER_ROLLER_CURRENT_CLASS, this === activeRoller)
                })
            },
            _refreshRollers: function() {
                var that = this;
                $.each(this._rollers, function(type) {
                    var correctIndex = that._rollerConfigs[type].getIndex(that._value);
                    this.update();
                    this._renderSelectedValue(correctIndex)
                })
            },
            _setRollerState: function(roller, selectedIndex) {
                if (selectedIndex !== roller.selectedIndex) {
                    var value = roller.valueItems[selectedIndex],
                        setValue = roller.setValue,
                        currentDate = this._value.getDate();
                    if (roller.type === MONTH) {
                        currentDate = Math.min(currentDate, getMaxMonthDay(this._value.getFullYear(), value));
                        this._value.setDate(currentDate)
                    }
                    else if (roller.type === YEAR) {
                        currentDate = Math.min(currentDate, getMaxMonthDay(value, this._value.getMonth()));
                        this._value.setDate(currentDate)
                    }
                    this._value[setValue](value);
                    roller.selectedIndex = selectedIndex
                }
                if (roller.type === YEAR) {
                    this._refreshMonthRoller();
                    this._refreshDayRoller()
                }
                if (roller.type === MONTH)
                    this._refreshDayRoller()
            },
            _refreshMonthRoller: function() {
                var monthRoller = this._rollers[MONTH];
                if (monthRoller) {
                    this._createRollerConfig(MONTH);
                    var monthRollerConfig = this._rollerConfigs[MONTH];
                    this._deferredRenderMonthTimeout = window.setTimeout(function() {
                        if (monthRollerConfig.displayItems.length === monthRoller.option("items").length)
                            return;
                        monthRoller.option({
                            items: monthRollerConfig.displayItems,
                            selectedIndex: monthRollerConfig.selectedIndex
                        })
                    }, 100)
                }
            },
            _refreshDayRoller: function() {
                var dayRoller = this._rollers[DAY];
                if (dayRoller) {
                    this._createRollerConfig(DAY);
                    var dayRollerConfig = this._rollerConfigs[DAY];
                    this._deferredRenderDayTimeout = window.setTimeout(function() {
                        if (dayRollerConfig.displayItems.length === dayRoller.option("items").length)
                            return;
                        dayRoller.option({
                            items: dayRollerConfig.displayItems,
                            selectedIndex: dayRollerConfig.selectedIndex
                        })
                    }, 100)
                }
            },
            _createRollerConfigs: function(format) {
                var that = this;
                format = format || that.option("format");
                that._rollerConfigs = {};
                $.each(that._getFormatPattern(format).split(/\W+/), function(_, formatPart) {
                    $.each(DATE_COMPONENTS_INFO, function(componentName, componentInfo) {
                        if ($.inArray(formatPart, componentInfo.possibleFormats) > -1)
                            that._createRollerConfig(componentName)
                    })
                })
            },
            _getFormatPattern: function(format) {
                var culture = Globalize.culture(this.option("culture")),
                    result = "";
                if (format === "date")
                    result = culture.calendar.patterns.d;
                else if (format === "time")
                    result = culture.calendar.patterns.t;
                else if (format === "datetime")
                    result = [culture.calendar.patterns.d, culture.calendar.patterns.t].join(" ");
                return result
            },
            _createRollerConfig: function(componentName) {
                var componentInfo = DATE_COMPONENTS_INFO[componentName],
                    valueRange = this._calculateRollerConfigValueRange(componentName),
                    startValue = valueRange.startValue,
                    endValue = valueRange.endValue,
                    formatter = componentInfo.formatter,
                    showNames = this.option("showNames"),
                    curDate = this._value;
                var config = {
                        type: componentName,
                        setValue: componentInfo.setter,
                        valueItems: [],
                        displayItems: [],
                        getIndex: function(value) {
                            return value[componentInfo.getter]() - startValue
                        }
                    };
                for (var i = startValue; i <= endValue; i++) {
                    config.valueItems.push(i);
                    config.displayItems.push(formatter(i, showNames, curDate))
                }
                config.selectedIndex = config.getIndex(this._value);
                this._rollerConfigs[componentName] = config
            },
            _calculateRollerConfigValueRange: function(componentName) {
                var curDate = this._value,
                    minDate = this.option("minDate"),
                    maxDate = this.option("maxDate"),
                    minYear = curDate.getFullYear() === minDate.getFullYear(),
                    minMonth = minYear && curDate.getMonth() === minDate.getMonth(),
                    maxYear = curDate.getFullYear() === maxDate.getFullYear(),
                    maxMonth = maxYear && curDate.getMonth() === maxDate.getMonth(),
                    componentInfo = DATE_COMPONENTS_INFO[componentName],
                    startValue = componentInfo.startValue,
                    endValue = componentInfo.endValue;
                if (componentName === YEAR) {
                    startValue = minDate.getFullYear();
                    endValue = maxDate.getFullYear()
                }
                if (componentName === MONTH) {
                    if (minYear)
                        startValue = minDate.getMonth();
                    if (maxYear)
                        endValue = maxDate.getMonth()
                }
                if (componentName === DAY) {
                    endValue = getMaxMonthDay(curDate.getFullYear(), curDate.getMonth());
                    if (minMonth)
                        startValue = minDate.getDate();
                    if (maxYear)
                        endValue = maxDate.getDate()
                }
                return {
                        startValue: startValue,
                        endValue: endValue
                    }
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"showNames":
                    case"minDate":
                    case"maxDate":
                    case"culture":
                    case"format":
                        this._renderRollers();
                        break;
                    case"visible":
                        this.callBase(name, value, prevValue);
                        if (value)
                            this._refreshRollers();
                        break;
                    case"value":
                        this._value = this._valueOption();
                        this._renderRollers();
                        break;
                    default:
                        this.callBase(name, value, prevValue)
                }
            },
            _dispose: function() {
                clearTimeout(this._deferredRenderDayTimeout);
                clearTimeout(this._deferredRenderMonthTimeout);
                this.callBase()
            }
        }));
        DX.registerComponent("dxDateBox", ui.dxTextEditor.inherit({
            ctor: function(element, options) {
                options = options || {};
                var preferCalendar = devices.current().platform === "generic" && (options.format === "date" || !options.format),
                    useCalendar = options && options.useCalendar;
                if (useCalendar === undefined)
                    useCalendar = preferCalendar;
                if (useCalendar)
                    new ui.dxCalendarPicker(element, options);
                else
                    this.callBase(element, options)
            },
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    format: "date",
                    value: new Date,
                    min: new Date(1),
                    max: new Date($.now() + TEN_YEARS),
                    useCalendar: false,
                    useNativePicker: true
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function(device) {
                                return device.win8 || device.android && !(device.version[0] > 4 || device.version[0] == 4 && device.version[1] >= 4)
                            },
                            options: {useNativePicker: false}
                        }])
            },
            _init: function() {
                this.callBase();
                this._initFormat()
            },
            _render: function() {
                this.callBase();
                this._element().addClass(DATEBOX_CLASS);
                this._renderDatePicker()
            },
            _renderDatePicker: function() {
                if (this._usingNativeDatePicker() || this.option("readOnly")) {
                    if (this._datePicker) {
                        this._datePicker._element().remove();
                        this._datePicker = null
                    }
                    return
                }
                var datePickerOptions = {
                        value: this.option("value"),
                        format: this.option("format"),
                        title: this._getDataPickerTitle(),
                        minDate: this.option("min"),
                        maxDate: this.option("max")
                    };
                if (this._datePicker)
                    this._datePicker.option(datePickerOptions);
                else {
                    this._datePicker = $("<div>").appendTo(this._element()).dxDatePicker($.extend(datePickerOptions, {hidingAction: $.proxy(function(e) {
                            this.option("value", e.component.option("value"))
                        }, this)})).dxDatePicker("instance");
                    var inputClickAction = this._createAction(function(e) {
                            e.component._datePicker.show()
                        });
                    this._input().on(events.addNamespace("dxclick", this.NAME), function(e) {
                        return inputClickAction({jQuery: e})
                    })
                }
            },
            _initFormat: function() {
                var format = this.option("format");
                if ($.inArray(format, SUPPORTED_FORMATS) === -1) {
                    format = "date";
                    this.option("format", format)
                }
                else if (format === "datetime" && !support.inputType(format))
                    format = "datetime-local";
                this.option("mode", format)
            },
            _usingNativeDatePicker: function() {
                return support.inputType(this.option("mode")) && this.option("useNativePicker")
            },
            _readOnlyPropValue: function() {
                if (this._usingNativeDatePicker())
                    return this.callBase();
                return true
            },
            _handleValueChangeEvent: function() {
                var value = fromStandardDateFormat(this._input().val()),
                    modelValue = new Date(this.option("value") && this.option("value").valueOf()),
                    newValue = mergeDates(modelValue, value, this.option("mode"));
                this.option({value: newValue});
                if (newValue !== modelValue)
                    this._renderValue()
            },
            _renderValue: function() {
                var mode = this.option("mode"),
                    patternKey = FORMATS_MAP[mode],
                    pattern = support.inputType(mode) ? false : globalize.culture().calendar.patterns[patternKey],
                    value = toStandardDateFormat(this.option("value"), mode, pattern);
                this._input().val(value);
                this._togglePlaceholderVisibility(value === "" || value === null)
            },
            _renderProps: function() {
                this.callBase();
                this._input().attr("autocomplete", "off")
            },
            _getDataPickerTitle: function() {
                var result = this.option("placeholder");
                if (!result) {
                    var format = this.option("format");
                    if (format === "time")
                        result = Globalize.localize("dxDateBox-simulatedDataPickerTitleTime");
                    else if (format === "date")
                        result = Globalize.localize("dxDateBox-simulatedDataPickerTitleDate");
                    else if (format === "datetime")
                        result = Globalize.localize("dxDateBox-simulatedDataPickerTitleDateTime")
                }
                return result
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"useCalendar":
                        break;
                    case"format":
                        this._initFormat();
                        this._renderValue();
                        this._renderDatePicker();
                        break;
                    case"readOnly":
                        this._invalidate();
                        break;
                    case"useNativePicker":
                        this._renderDatePicker();
                        break;
                    case"placeholder":
                        if (this._datePicker)
                            this._datePicker.option("title", this._getDataPickerTitle());
                        break;
                    case"type":
                        throw new Error("type cannot be changed after instantiation");
                        break;
                    case"min":
                    case"max":
                        if (this._datePicker)
                            this._datePicker.option(name + "Date", value);
                        break;
                    case"value":
                        this._renderValue();
                        this._renderDatePicker();
                    default:
                        this.callBase(name, value, prevValue)
                }
            }
        }));
        ui.dxDatePicker.__internals = {
            DATEPICKER_CLASS: DATEPICKER_CLASS,
            DATEPICKER_WRAPPER_CLASS: DATEPICKER_WRAPPER_CLASS,
            DATEPICKER_ROLLER_CONTAINER_CLASS: DATEPICKER_ROLLER_CONTAINER_CLASS,
            DATEPICKER_ROLLER_CLASS: DATEPICKER_ROLLER_CLASS,
            DATEPICKER_ROLLER_ACTIVE_CLASS: DATEPICKER_ROLLER_ACTIVE_CLASS,
            DATEPICKER_ROLLER_ITEM_CLASS: DATEPICKER_ROLLER_ITEM_CLASS,
            DATEPICKER_ROLLER_ITEM_SELECTED_CLASS: DATEPICKER_ROLLER_ITEM_SELECTED_CLASS,
            DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS: DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS,
            DATEPICKER_ROLLER_BUTTON_UP_CLASS: DATEPICKER_ROLLER_BUTTON_UP_CLASS,
            DATEPICKER_ROLLER_BUTTON_DOWN_CLASS: DATEPICKER_ROLLER_BUTTON_DOWN_CLASS,
            DATEPICKER_ROLLER_CURRENT_CLASS: DATEPICKER_ROLLER_CURRENT_CLASS
        };
        ui.dxDateBox.__internals = {
            toStandardDateFormat: toStandardDateFormat,
            fromStandardDateFormat: fromStandardDateFormat,
            FORMATS_MAP: FORMATS_MAP
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.loadIndicator.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var LOADINDICATOR_CLASS = "dx-loadindicator",
            LOADINDICATOR_WRAPPER = "dx-loadindicator-wrapper",
            LOADINDICATOR_ICON = "dx-loadindicator-icon",
            LOADINDICATOR_SEGMENT = "dx-loadindicator-segment",
            LOADINDICATOR_SEGMENT_N = "dx-loadindicator-segment",
            LOADINDICATOR_SEGMENT_WIN8 = "dx-loadindicator-win8-segment",
            LOADINDICATOR_SEGMENT_N_WIN8 = "dx-loadindicator-win8-segment",
            LOADINDICATOR_INNER_SEGMENT_WIN8 = "dx-loadindicator-win8-inner-segment",
            LOADINDICATOR_IMAGE = "dx-loadindicator-image";
        DX.registerComponent("dxLoadIndicator", ui.Widget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({indicatorSrc: ""})
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function() {
                                var realDevice = DevExpress.devices.real(),
                                    obsoleteAndroid = realDevice.platform === "android" && !/chrome/i.test(navigator.userAgent);
                                return DevExpress.browser.msie && DevExpress.browser.version < 10 || obsoleteAndroid
                            },
                            options: {viaImage: true}
                        }])
            },
            _init: function() {
                this.callBase();
                this._element().addClass(LOADINDICATOR_CLASS)
            },
            _render: function() {
                this._renderWrapper();
                this._renderMarkup();
                this.callBase()
            },
            _renderWrapper: function() {
                this._$wrapper = $("<div>").addClass(LOADINDICATOR_WRAPPER);
                this._element().append(this._$wrapper)
            },
            _renderMarkup: function() {
                if (DX.support.animation && !this.option("viaImage") && !this.option("indicatorSrc"))
                    this._renderMarkupForAnimation();
                else
                    this._renderMarkupForImage()
            },
            _renderMarkupForAnimation: function() {
                this._$indicator = $("<div>").addClass(LOADINDICATOR_ICON);
                for (var i = 15; i >= 0; --i) {
                    var $segment = $("<div>").addClass(LOADINDICATOR_SEGMENT).addClass(LOADINDICATOR_SEGMENT_N + i);
                    this._$indicator.append($segment)
                }
                for (var i = 1; i <= 5; ++i) {
                    var $innerSegment = $("<div>").addClass(LOADINDICATOR_INNER_SEGMENT_WIN8),
                        $segment = $("<div>").addClass(LOADINDICATOR_SEGMENT_WIN8).addClass(LOADINDICATOR_SEGMENT_N_WIN8 + i);
                    $segment.append($innerSegment);
                    this._$indicator.append($segment)
                }
                this._$wrapper.append(this._$indicator)
            },
            _renderMarkupForImage: function() {
                var indicatorSrc = this.option("indicatorSrc");
                this._$wrapper.addClass(LOADINDICATOR_IMAGE);
                if (indicatorSrc)
                    this._$wrapper.css("background-image", "url(" + indicatorSrc + ")")
            },
            _renderDimensions: function() {
                this.callBase();
                this._updateContentSize()
            },
            _updateContentSize: function() {
                var $element = this._element(),
                    width = this.option("width"),
                    height = this.option("height");
                if (width || height) {
                    width = this._element().width();
                    height = this._element().height();
                    var minDimention = Math.min(height, width);
                    this._$wrapper.css({
                        height: minDimention,
                        width: minDimention,
                        "margin-top": (height - minDimention) / 2,
                        "margin-left": (width - minDimention) / 2
                    });
                    if (this._$indicator)
                        this._$indicator.find("." + LOADINDICATOR_SEGMENT).css("border-width", 0.125 * minDimention)
                }
            },
            _clean: function() {
                this.callBase();
                this._removeMarkupForAnimation();
                this._removeMarkupForImage()
            },
            _removeMarkupForAnimation: function() {
                if (this._$indicator)
                    this._$indicator.remove()
            },
            _removeMarkupForImage: function() {
                this._$wrapper.css("background-image", "none")
            },
            _optionChanged: function(name) {
                switch (name) {
                    case"indicatorSrc":
                        this._invalidate();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.loadPanel.js */
    (function($, DX, undefined) {
        var ui = DX.ui;
        var LOADPANEL_CLASS = "dx-loadpanel",
            LOADPANEL_WRAPPER_CLASS = "dx-loadpanel-wrapper",
            LOADPANEL_INDICATOR_CLASS = "dx-loadpanel-indicator",
            LOADPANEL_MESSAGE_CLASS = "dx-loadpanel-message",
            LOADPANEL_CONTENT_CLASS = "dx-loadpanel-content",
            LOADPANEL_CONTENT_WRAPPER_CLASS = "dx-loadpanel-content-wrapper",
            LOADPANEL_PANE_HIDDEN_CLASS = "dx-loadpanel-pane-hidden";
        DX.registerComponent("dxLoadPanel", ui.dxOverlay.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    message: Globalize.localize("Loading"),
                    width: 222,
                    height: 90,
                    animation: null,
                    showIndicator: true,
                    indicatorSrc: "",
                    showPane: true,
                    delay: 0
                })
            },
            _init: function() {
                this.callBase.apply(this, arguments);
                this._$contentWrapper = $("<div>").addClass(LOADPANEL_CONTENT_WRAPPER_CLASS);
                this._$contentWrapper.appendTo(this._container())
            },
            _render: function() {
                this.callBase();
                this._element().addClass(LOADPANEL_CLASS);
                this._wrapper().addClass(LOADPANEL_WRAPPER_CLASS)
            },
            _renderContentImpl: function() {
                this.callBase();
                this.content().addClass(LOADPANEL_CONTENT_CLASS);
                this._togglePaneVisible();
                this._cleanPreviousContent();
                this._renderLoadIndicator();
                this._renderMessage()
            },
            _makeVisible: function() {
                var delay = this.option("delay");
                if (!delay)
                    return this.callBase();
                var deferred = $.Deferred();
                var callBase = $.proxy(this.callBase, this);
                this._clearShowTimeout();
                this._showTimeout = setTimeout(function() {
                    callBase().done(function() {
                        deferred.resolve()
                    })
                }, delay);
                return deferred.promise()
            },
            _makeHidden: function() {
                this._clearShowTimeout();
                return this.callBase()
            },
            _clearShowTimeout: function() {
                clearTimeout(this._showTimeout)
            },
            _renderMessage: function() {
                var message = this.option("message");
                if (!message)
                    return;
                var $message = $("<div>").addClass(LOADPANEL_MESSAGE_CLASS).text(message);
                this._$contentWrapper.append($message)
            },
            _renderLoadIndicator: function() {
                if (!this.option("showIndicator"))
                    return;
                this._$indicator = $("<div>").addClass(LOADPANEL_INDICATOR_CLASS).dxLoadIndicator({indicatorSrc: this.option("indicatorSrc")}).appendTo(this._$contentWrapper)
            },
            _cleanPreviousContent: function() {
                this.content().find("." + LOADPANEL_MESSAGE_CLASS).remove();
                this.content().find("." + LOADPANEL_INDICATOR_CLASS).remove()
            },
            _togglePaneVisible: function() {
                this.content().toggleClass(LOADPANEL_PANE_HIDDEN_CLASS, !this.option("showPane"))
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"delay":
                        break;
                    case"message":
                    case"showIndicator":
                        this._cleanPreviousContent();
                        this._renderLoadIndicator();
                        this._renderMessage();
                        break;
                    case"showPane":
                        this._togglePaneVisible();
                        break;
                    case"indicatorSrc":
                        if (this._$indicator)
                            this._$indicator.dxLoadIndicator({indicatorSrc: this.option("indicatorSrc")});
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _dispose: function() {
                this._clearShowTimeout();
                this.callBase()
            },
            _defaultHideTopOverlayHandler: $.noop
        }));
        ui.dxLoadPanel.__internals = {
            LOADPANEL_CLASS: LOADPANEL_CLASS,
            LOADPANEL_WRAPPER_CLASS: LOADPANEL_WRAPPER_CLASS,
            LOADPANEL_MESSAGE_CLASS: LOADPANEL_MESSAGE_CLASS,
            LOADPANEL_CONTENT_CLASS: LOADPANEL_CONTENT_CLASS,
            LOADPANEL_PANE_HIDDEN_CLASS: LOADPANEL_PANE_HIDDEN_CLASS
        }
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.lookup.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events;
        var LOOKUP_CLASS = "dx-lookup",
            LOOKUP_SELECTED_CLASS = LOOKUP_CLASS + "-selected",
            LOOKUP_SEARCH_CLASS = LOOKUP_CLASS + "-search",
            LOOKUP_SEARCH_WRAPPER_CLASS = LOOKUP_CLASS + "-search-wrapper",
            LOOKUP_FIELD_CLASS = LOOKUP_CLASS + "-field",
            LOOKUP_FIELD_WRAPPER_CLASS = LOOKUP_FIELD_CLASS + "-wrapper",
            LOOKUP_POPUP_CLASS = LOOKUP_CLASS + "-popup",
            LOOKUP_POPUP_WRAPPER_CLASS = LOOKUP_POPUP_CLASS + "-wrapper",
            LOOKUP_POPUP_SEARCH_CLASS = LOOKUP_POPUP_CLASS + "-search",
            LOOKUP_POPOVER_MODE = LOOKUP_CLASS + "-popover-mode",
            LOOKUP_EMPTY_CLASS = LOOKUP_CLASS + "-empty",
            LIST_ITEM_SELECTOR = ".dx-list-item",
            LIST_ITEM_DATA_KEY = "dxListItemData",
            POPUP_HIDE_TIMEOUT = 200;
        DX.registerComponent("dxLookup", ui.dxEditor.inherit({
            _deprecatedOptions: {
                shownAction: {
                    since: "14.1",
                    message: "Use the 'openAction' option instead."
                },
                hiddenAction: {
                    since: "14.1",
                    message: "Use the 'closeAction' option instead."
                }
            },
            _optionAliases: {
                openAction: "shownAction",
                closeAction: "hiddenAction"
            },
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    items: [],
                    dataSource: null,
                    value: undefined,
                    displayValue: undefined,
                    title: "",
                    titleTemplate: "title",
                    valueExpr: null,
                    displayExpr: "this",
                    placeholder: Globalize.localize("Select"),
                    searchPlaceholder: Globalize.localize("Search"),
                    searchEnabled: true,
                    noDataText: Globalize.localize("dxCollectionContainerWidget-noDataText"),
                    searchTimeout: 1000,
                    minFilterLength: 0,
                    fullScreen: false,
                    valueChangeAction: null,
                    itemTemplate: null,
                    itemRender: null,
                    showCancelButton: true,
                    cancelButtonText: Globalize.localize("Cancel"),
                    showClearButton: false,
                    clearButtonText: Globalize.localize("Clear"),
                    showDoneButton: false,
                    doneButtonText: Globalize.localize("Done"),
                    contentReadyAction: null,
                    shownAction: null,
                    openAction: null,
                    hiddenAction: null,
                    closeAction: null,
                    popupWidth: function() {
                        return $(window).width() * 0.8
                    },
                    popupHeight: function() {
                        return $(window).height() * 0.8
                    },
                    shading: true,
                    closeOnOutsideClick: false,
                    position: undefined,
                    animation: undefined,
                    pullRefreshEnabled: false,
                    autoPagingEnabled: true,
                    useNativeScrolling: true,
                    pullingDownText: Globalize.localize("dxList-pullingDownText"),
                    pulledDownText: Globalize.localize("dxList-pulledDownText"),
                    refreshingText: Globalize.localize("dxList-refreshingText"),
                    pageLoadingText: Globalize.localize("dxList-pageLoadingText"),
                    scrollAction: null,
                    pullRefreshAction: null,
                    pageLoadingAction: null,
                    showNextButton: false,
                    nextButtonText: Globalize.localize("dxList-nextButtonText"),
                    grouped: false,
                    groupTemplate: "group",
                    groupRender: null,
                    usePopover: false
                })
            },
            _defaultOptionsRules: function() {
                return this.callBase().slice(0).concat([{
                            device: function(device) {
                                return !DX.support.nativeScrolling
                            },
                            options: {useNativeScrolling: false}
                        }, {
                            device: function(device) {
                                return !DX.support.nativeScrolling && !DX.devices.isSimulator() && DX.devices.real().platform === "generic" && device.platform === "generic"
                            },
                            options: {
                                showNextButton: true,
                                autoPagingEnabled: false
                            }
                        }, {
                            device: {
                                platform: "win8",
                                phone: true
                            },
                            options: {
                                showCancelButton: false,
                                fullScreen: true
                            }
                        }, {
                            device: {
                                platform: "win8",
                                phone: false
                            },
                            options: {popupWidth: function() {
                                    return $(window).width()
                                }}
                        }, {
                            device: [{
                                    platform: "ios",
                                    phone: true
                                }, {
                                    platform: "ios7",
                                    phone: true
                                }],
                            options: {fullScreen: true}
                        }, {
                            device: [{
                                    platform: "ios",
                                    tablet: true
                                }, {
                                    platform: "ios7",
                                    tablet: true
                                }],
                            options: {
                                popupWidth: function() {
                                    return Math.min($(window).width(), $(window).height()) * 0.4
                                },
                                popupHeight: function() {
                                    return Math.min($(window).width(), $(window).height()) * 0.4
                                },
                                usePopover: true
                            }
                        }])
            },
            _optionsByReference: function() {
                return $.extend(this.callBase(), {value: true})
            },
            _init: function() {
                this.callBase();
                this._initDataSource();
                this._searchTimer = null;
                this._compileValueGetter();
                this._compileDisplayGetter();
                this._suppressValueChangeAction();
                if (!this._dataSource)
                    this._itemsToDataSource()
            },
            _compileValueGetter: function() {
                this._valueGetter = DX.data.utils.compileGetter(this._valueGetterExpr())
            },
            _valueGetterExpr: function() {
                return this.option("valueExpr") || "this"
            },
            _compileDisplayGetter: function() {
                this._displayGetter = DX.data.utils.compileGetter(this.option("displayExpr"))
            },
            _itemsToDataSource: function() {
                this._dataSource = new DevExpress.data.DataSource(this.option("items"))
            },
            _render: function() {
                this.callBase();
                this._element().addClass(LOOKUP_CLASS).toggleClass(LOOKUP_POPOVER_MODE, this.option("usePopover"));
                this._renderField();
                this._needRenderContent = true;
                this._calcSelectedItem($.proxy(this._setFieldText, this))
            },
            _renderContent: $.noop,
            _renderContentImpl: $.noop,
            _renderField: function() {
                var fieldClickAction = this._createAction(this._handleFieldClick);
                this._$fieldWrapper = $("<div>").addClass(LOOKUP_FIELD_WRAPPER_CLASS);
                this._$field = $("<div>").addClass(LOOKUP_FIELD_CLASS).appendTo(this._$fieldWrapper).on(events.addNamespace("dxclick", this.NAME), function(e) {
                    fieldClickAction({jQueryEvent: e})
                });
                this._$fieldWrapper.appendTo(this._element())
            },
            _handleFieldClick: function(args) {
                var that = args.component;
                that._renderContentIfNeed();
                that._setListDataSource();
                that._refreshSelected();
                that._popup.show();
                that._lastSelectedItem = that._selectedItem
            },
            _renderContentIfNeed: function() {
                if (this._needRenderContent) {
                    this._renderPopup();
                    this._needRenderContent = false
                }
            },
            _renderPopup: function() {
                var $popup = $("<div>").addClass(LOOKUP_POPUP_CLASS).appendTo(this._element());
                var popupOptions = {
                        rtlEnabled: this.option("rtlEnabled"),
                        showTitle: true,
                        title: this.option("title"),
                        titleTemplate: this._getTemplateByOption("titleTemplate"),
                        contentReadyAction: $.proxy(this._popupContentReadyAction, this),
                        cancelButton: this._getCancelButtonConfig(),
                        doneButton: this._getDoneButtonConfig(),
                        clearButton: this._getClearButtonConfig(),
                        shownAction: this._createActionByOption("shownAction"),
                        hiddenAction: this._createActionByOption("hiddenAction")
                    };
                this._popup = this.option("usePopover") && !this.option("fullScreen") ? this._createPopover($popup, popupOptions) : this._createPopup($popup, popupOptions);
                this._setPopupOption("position", "position");
                this._setPopupOption("animation", "animation");
                this._setPopupOption("popupWidth", "width");
                this._setPopupOption("popupHeight", "height");
                this._popup._wrapper().addClass(LOOKUP_POPUP_WRAPPER_CLASS).toggleClass(LOOKUP_POPUP_SEARCH_CLASS, this.option("searchEnabled"))
            },
            _setPopupOption: function(option, popupOption) {
                var option = this.option(option);
                option = option === undefined ? this._popup.initialOption(popupOption) : option;
                this._popup.option(popupOption, option)
            },
            _createPopover: function($element, options) {
                return $element.dxPopover($.extend(options, {target: this._element()})).dxPopover("instance")
            },
            _createPopup: function($element, options) {
                return $element.dxPopup($.extend(options, {
                        fullScreen: this.option("fullScreen"),
                        shading: this.option("shading"),
                        closeOnOutsideClick: this.option("closeOnOutsideClick")
                    })).dxPopup("instance")
            },
            _getCancelButtonConfig: function() {
                return this.option("showCancelButton") ? {text: this.option("cancelButtonText")} : null
            },
            _getDoneButtonConfig: function() {
                return this.option("showDoneButton") ? {
                        text: this.option("doneButtonText"),
                        clickAction: $.proxy(function() {
                            this.option("value", this._valueGetter(this._lastSelectedItem))
                        }, this)
                    } : null
            },
            _getClearButtonConfig: function() {
                return this.option("showClearButton") ? {
                        text: this.option("clearButtonText"),
                        clickAction: $.proxy(function() {
                            this.option("value", "")
                        }, this)
                    } : null
            },
            _renderCancelButton: function() {
                this._popup && this._popup.option("cancelButton", this._getCancelButtonConfig())
            },
            _renderDoneButton: function() {
                this._popup && this._popup.option("doneButton", this._getDoneButtonConfig())
            },
            _renderClearButton: function() {
                this._popup && this._popup.option("clearButton", this._getClearButtonConfig())
            },
            _popupContentReadyAction: function() {
                this._renderSearch();
                this._renderList()
            },
            _renderSearch: function() {
                this._$search = $("<div>").addClass(LOOKUP_SEARCH_CLASS).dxTextBox({
                    mode: "search",
                    placeholder: this._getSearchPlaceholder(),
                    valueChangeEvent: "change input",
                    valueChangeAction: $.proxy(this._searchChangedHandler, this),
                    rtlEnabled: this.option("rtlEnabled")
                }).appendTo(this._popup.content()).wrap($("<div>").addClass(LOOKUP_SEARCH_WRAPPER_CLASS).toggle(this.option("searchEnabled")));
                this._search = this._$search.dxTextBox("instance")
            },
            _getSearchPlaceholder: function() {
                var minFilterLength = this.option("minFilterLength"),
                    placeholder = this.option("searchPlaceholder");
                if (minFilterLength && placeholder === Globalize.localize("Search"))
                    return utils.stringFormat(Globalize.localize("dxLookup-searchPlaceholder"), minFilterLength);
                return placeholder
            },
            _renderList: function() {
                this._list = $("<div>").appendTo(this._popup.content()).dxList({
                    dataSource: null,
                    itemClickAction: $.proxy(function(e) {
                        this._toggleSelectedClass(e.jQueryEvent);
                        this._updateOptions(e)
                    }, this),
                    itemRenderedAction: $.proxy(function(e) {
                        this._setSelectedClass(e.itemElement, e.itemData)
                    }, this),
                    itemRender: this._getItemRender(),
                    itemTemplate: this._getTemplateByOption("itemTemplate"),
                    noDataText: this.option("noDataText"),
                    pullRefreshEnabled: this.option("pullRefreshEnabled"),
                    autoPagingEnabled: this.option("autoPagingEnabled"),
                    useNativeScrolling: this.option("useNativeScrolling"),
                    pullingDownText: this.option("pullingDownText"),
                    pulledDownText: this.option("pulledDownText"),
                    refreshingText: this.option("refreshingText"),
                    pageLoadingText: this.option("pageLoadingText"),
                    scrollAction: this.option("scrollAction"),
                    pullRefreshAction: this.option("pullRefreshAction"),
                    pageLoadingAction: this.option("pageLoadingAction"),
                    showNextButton: this.option("showNextButton"),
                    nextButtonText: this.option("nextButtonText"),
                    grouped: this.option("grouped"),
                    groupTemplate: this._getTemplateByOption("groupTemplate"),
                    groupRender: this.option("groupRender"),
                    rtlEnabled: this.option("rtlEnabled")
                }).data("dxList");
                if (this._needSetItemRenderToList) {
                    this._updateListItemRender();
                    this._needSetItemRenderToList = false
                }
                this._setListDataSource();
                this._list.option("contentReadyAction", this.option("contentReadyAction"));
                this._list._fireContentReadyAction()
            },
            _setListDataSource: function(force) {
                if (!this._list)
                    return;
                var needsToLoad = this._search.option("value").length >= this.option("minFilterLength"),
                    dataSourceLoaded = !!this._list.option("dataSource"),
                    skip = needsToLoad === dataSourceLoaded;
                if (!force && skip)
                    return;
                this._list.option("dataSource", needsToLoad ? this._dataSource : null);
                if (!needsToLoad)
                    this._list.option("items", undefined)
            },
            _refreshSelected: function() {
                var that = this;
                if (!that._list)
                    return;
                $.each(this._list._element().find(LIST_ITEM_SELECTOR), function() {
                    var item = $(this);
                    that._setSelectedClass(item, item.data(LIST_ITEM_DATA_KEY))
                })
            },
            _calcSelectedItem: function(callback) {
                var ds = this._dataSource,
                    store,
                    valueExpr,
                    thisWidget = this,
                    value = this._unwrapedValue();
                function handleLoadSuccess(result) {
                    thisWidget._selectedItem = result;
                    callback()
                }
                if (!ds || value === undefined) {
                    this._selectedItem = undefined;
                    callback();
                    return
                }
                store = ds.store();
                valueExpr = this._valueGetterExpr();
                if (valueExpr === store.key() || valueExpr === "this" || store instanceof DX.data.CustomStore)
                    store.byKey(value).done(handleLoadSuccess);
                else
                    store.load({filter: [valueExpr, value]}).done(function(result) {
                        handleLoadSuccess(result[0])
                    })
            },
            _unwrapedValue: function() {
                var value = this.option("value");
                var valueExpr = this._valueGetterExpr();
                if (!this._dataSource && valueExpr !== "this")
                    return value;
                var key = this._dataSource.store().key();
                if (key && typeof value === "object")
                    value = value[key];
                return $.isFunction(value) ? value() : value
            },
            _setFieldText: function(text) {
                if (!arguments.length)
                    text = this._getDisplayText();
                this._$field.text(text);
                this.option("displayValue", text);
                this._toggleEmptyClass()
            },
            _getDisplayText: function() {
                if (this.option("value") === undefined || !this._dataSource)
                    return this.option("placeholder");
                return this._displayGetter(this._selectedItem) || this.option("placeholder")
            },
            _searchChangedHandler: function() {
                if (!this._search)
                    return;
                var searchValue = this._search.option("value"),
                    needsToLoad = searchValue.length >= this.option("minFilterLength");
                clearTimeout(this._searchTimer);
                this._search.option("placeholder", this._getSearchPlaceholder());
                if (!needsToLoad) {
                    this._setListDataSource();
                    return
                }
                if (this.option("searchTimeout"))
                    this._searchTimer = setTimeout($.proxy(this._doSearch, this, searchValue), this.option("searchTimeout"));
                else
                    this._doSearch(searchValue)
            },
            _doSearch: function(searchValue) {
                if (!this._dataSource)
                    return;
                if (!arguments.length)
                    searchValue = this.option("searchEnabled") ? this._search.option("value") : "";
                this._filterStore(searchValue).done($.proxy(function() {
                    if (this._dataSource.items().length)
                        this._setListDataSource()
                }, this))
            },
            _filterStore: function(searchValue) {
                if (!this._dataSource.searchExpr())
                    this._dataSource.searchExpr(this.option("displayExpr"));
                this._dataSource.searchValue(searchValue);
                this._dataSource.pageIndex(0);
                return this._dataSource.load()
            },
            _updateOptions: function(e) {
                if (this._lastSelectedItem === e.itemData)
                    this._updateAndHidePopup();
                this._lastSelectedItem = e.itemData;
                if (!this.option("showDoneButton"))
                    this._updateAndHidePopup()
            },
            _setSelectedClass: function(item, itemData) {
                var selected = this._optionValuesEqual("value", this._valueGetter(itemData), this.option("value"));
                item.toggleClass(LOOKUP_SELECTED_CLASS, selected)
            },
            _getItemRender: function() {
                if (!this.option("itemTemplate"))
                    return this.option("itemRender") || $.proxy(this._displayGetter, this)
            },
            _toggleSelectedClass: function(e) {
                var $selectedItem = this._list._element().find("." + LOOKUP_SELECTED_CLASS);
                if ($selectedItem.length)
                    $selectedItem.removeClass(LOOKUP_SELECTED_CLASS);
                $(e.target).closest(LIST_ITEM_SELECTOR).addClass(LOOKUP_SELECTED_CLASS)
            },
            _toggleEmptyClass: function() {
                var empty = !this._selectedItem;
                this._element().toggleClass(LOOKUP_EMPTY_CLASS, empty)
            },
            _hidePopup: function() {
                this._popup.hide()
            },
            _updateAndHidePopup: function() {
                this.option("value", this._valueGetter(this._lastSelectedItem));
                clearTimeout(this._hidePopupTimer);
                this._hidePopupTimer = setTimeout($.proxy(this._hidePopup, this), POPUP_HIDE_TIMEOUT);
                this._setFieldText(this._displayGetter(this._lastSelectedItem))
            },
            _updateListItemRender: function() {
                if (this._list)
                    this._list.option("itemRender", this._getItemRender());
                else
                    this._needSetItemRenderToList = true
            },
            _updateListItemTemplate: function() {
                if (this._list)
                    this._list.option("itemTemplate", this.option("itemTemplate"))
            },
            _handleDataSourceChanged: function(items) {
                this._calcSelectedItem($.proxy(this._setFieldText, this))
            },
            _clean: function() {
                if (this._popup)
                    this._popup._element().remove();
                if (this._$field)
                    this._$field.remove();
                if (this._$fieldWrapper)
                    this._$fieldWrapper.remove()
            },
            _dispose: function() {
                clearTimeout(this._searchTimer);
                clearTimeout(this._hidePopupTimer);
                $(window).off(events.addNamespace("popstate", this.NAME));
                this.callBase()
            },
            _changeListOption: function(name, value) {
                if (this._list)
                    this._list.option(name, value)
            },
            _changePopupOption: function(name, value) {
                if (this._popup)
                    this._popup.option(name, value)
            },
            _optionChanged: function(name, value, previousValue) {
                switch (name) {
                    case"valueExpr":
                    case"value":
                        this._calcSelectedItem($.proxy(function() {
                            if (name === "value")
                                this._raiseValueChangeAction(value, previousValue, {selectedItem: this._selectedItem});
                            this._compileValueGetter();
                            this._compileDisplayGetter();
                            this._refreshSelected();
                            this._setFieldText()
                        }, this));
                        break;
                    case"displayExpr":
                        this._compileDisplayGetter();
                        this._updateListItemRender();
                        this._refreshSelected();
                        this._setFieldText();
                        break;
                    case"displayValue":
                        break;
                    case"itemRender":
                        this._updateListItemRender();
                    case"itemTemplate":
                        this._updateListItemTemplate();
                        break;
                    case"items":
                    case"dataSource":
                        if (name === "items")
                            this._itemsToDataSource();
                        else
                            this._initDataSource();
                        this._setListDataSource(true);
                        this._compileValueGetter();
                        this._calcSelectedItem($.proxy(this._setFieldText, this));
                        break;
                    case"searchEnabled":
                        if (this._$search)
                            this._$search.toggle(value);
                        if (this._popup)
                            this._popup._wrapper().toggleClass(LOOKUP_POPUP_SEARCH_CLASS, value);
                        break;
                    case"minFilterLength":
                        this._setListDataSource();
                        this._setFieldText();
                        this._searchChangedHandler();
                        break;
                    case"placeholder":
                        this._setFieldText();
                        break;
                    case"searchPlaceholder":
                        if (this._$search)
                            this._$search.dxTextBox("instance").option("placeholder", value);
                        break;
                    case"shownAction":
                    case"hiddenAction":
                    case"openAction":
                    case"closeAction":
                    case"animation":
                        this._renderPopup();
                        break;
                    case"title":
                    case"titleTemplate":
                        this._changePopupOption(name, value);
                        break;
                    case"position":
                    case"shading":
                    case"closeOnOutsideClick":
                        if (!this.option("usePopover"))
                            this._changePopupOption(name, value);
                        break;
                    case"fullScreen":
                        if (this._popup)
                            if (!this.option("usePopover"))
                                this._popup.option(name, value);
                            else
                                this._renderPopup();
                        break;
                    case"clearButtonText":
                    case"showClearButton":
                        this._renderClearButton();
                        break;
                    case"cancelButtonText":
                    case"showCancelButton":
                        this._renderCancelButton();
                        break;
                    case"doneButtonText":
                    case"showDoneButton":
                        this._renderDoneButton();
                        break;
                    case"popupWidth":
                        this._changePopupOption("width", value === "auto" ? this.initialOption("popupWidth") : value);
                        break;
                    case"popupHeight":
                        this._changePopupOption("height", value === "auto" ? this.initialOption("popupHeight") : value);
                        break;
                    case"usePopover":
                        this._invalidate();
                        break;
                    case"pullRefreshEnabled":
                    case"autoPagingEnabled":
                    case"useNativeScrolling":
                    case"pullingDownText":
                    case"pulledDownText":
                    case"refreshingText":
                    case"pageLoadingText":
                    case"scrollAction":
                    case"pullRefreshAction":
                    case"pageLoadingAction":
                    case"showNextButton":
                    case"nextButtonText":
                    case"grouped":
                    case"groupRender":
                    case"noDataText":
                    case"contentReadyAction":
                        this._changeListOption(name, value);
                        break;
                    case"groupTemplate":
                        this._changeListOption(name, this._getTemplateByOption(name));
                    case"searchTimeout":
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            open: function() {
                this._renderContentIfNeed();
                this._popup.show()
            },
            close: function() {
                this._renderContentIfNeed();
                this._popup.hide()
            }
        }).include(ui.DataHelperMixin))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.autocomplete.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils;
        var KEY_DOWN = 40,
            KEY_UP = 38,
            KEY_ENTER = 13,
            KEY_ESC = 27,
            KEY_RIGHT = 39,
            KEY_TAB = 9,
            AUTOCOMPLETE_CLASS = "dx-autocomplete",
            AUTOCOMPLETE_POPUP_WRAPPER_CLASS = "dx-autocomplete-popup-wrapper",
            SELECTED_ITEM_CLASS = "dx-autocomplete-selected",
            SELECTED_ITEM_SELECTOR = "." + SELECTED_ITEM_CLASS,
            LIST_SELECTOR = ".dx-list",
            LIST_ITEM_SELECTOR = ".dx-list-item",
            LIST_ITEM_DATA_KEY = "dxListItemData",
            SEARCH_MODES = ["startswith", "contains", "endwith", "notcontains"],
            AUTOCOMPLETE_KEYDOWN_EVENT_NAME = events.addNamespace("keydown", "dxAutocomplete"),
            AUTOCOMPLETE_KEYUP_EVENT_NAME = events.addNamespace("keyup", "dxAutocomplete"),
            AUTOCOMPLETE_FOCUSIN_EVENT_NAME = events.addNamespace("focusin", "dxAutocomplete"),
            AUTOCOMPLETE_FOCUSOUT_EVENT_NAME = events.addNamespace("focusout", "dxAutocomplete");
        DX.registerComponent("dxAutocomplete", ui.dxDropDownEditor.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    value: "",
                    items: [],
                    dataSource: null,
                    itemTemplate: null,
                    itemRender: null,
                    minSearchLength: 1,
                    searchTimeout: 0,
                    searchMode: "contains",
                    displayExpr: "this",
                    valueChangeEvent: "change keyup",
                    shouldActivateFocusOut: true,
                    maxLength: null
                })
            },
            _listElement: function() {
                return this._dropDown.content().find(LIST_SELECTOR)
            },
            _listItemElement: function() {
                return this._dropDown.content().find(LIST_ITEM_SELECTOR)
            },
            _listSelectedItemElement: function() {
                return this._dropDown.content().find(this._getSelectedItemSelector())
            },
            _init: function() {
                this.callBase();
                this._validateSearchMode();
                this._compileDisplayGetter();
                this._initDataSource();
                this._fillDataSourceFromItemsIfNeeded()
            },
            _fillDataSourceFromItemsIfNeeded: function() {
                if (!this.option("dataSource") && this.option("items"))
                    this._itemsToDataSource()
            },
            _validateSearchMode: function() {
                var searchMode = this.option("searchMode"),
                    normalizedSearchMode = searchMode.toLowerCase();
                if ($.inArray(normalizedSearchMode, SEARCH_MODES) > -1)
                    return;
                throw Error(DX.utils.stringFormat("Search mode \"{0}\" is unavailable", searchMode));
            },
            _compileDisplayGetter: function() {
                this._displayGetter = DX.data.utils.compileGetter(this.option("displayExpr"))
            },
            _render: function() {
                this.callBase();
                this._element().addClass(AUTOCOMPLETE_CLASS);
                this._renderInputEvents()
            },
            _renderDimensions: function() {
                this.callBase();
                if (this._dropDown)
                    this._dropDown.option("width", this.option("width"))
            },
            _renderContentImpl: function() {
                this._caretPosition = {
                    start: 0,
                    end: 0
                };
                this._renderDropDownContainer()
            },
            _renderButton: function(hideButton) {
                this.callBase(hideButton === false ? false : true)
            },
            _renderInputEvents: function() {
                this._input().on(AUTOCOMPLETE_KEYDOWN_EVENT_NAME, $.proxy(this._handleInputKeyDown, this)).on(AUTOCOMPLETE_KEYUP_EVENT_NAME, $.proxy(this._handleInputKeyUp, this)).on(AUTOCOMPLETE_FOCUSIN_EVENT_NAME, $.proxy(function() {
                    this._setFocusSelection()
                }, this)).on(AUTOCOMPLETE_FOCUSOUT_EVENT_NAME, $.proxy(function() {
                    if (this.option("shouldActivateFocusOut"))
                        this._hideDropDown();
                    this._toggleElementSelectedClass(false)
                }, this))
            },
            _setFocusSelection: function() {
                this._toggleElementSelectedClass(true)
            },
            _hasUpdateEvent: function(eventName) {
                return eventName && this.option("valueUpdateEvent").indexOf(eventName) !== -1
            },
            _handleInputKeyDown: function(e) {
                var $list = this._listElement(),
                    preventedKeys = [KEY_TAB, KEY_UP, KEY_DOWN],
                    key = e.which;
                if ($list.is(":hidden"))
                    return;
                if ($.inArray(key, preventedKeys) > -1)
                    e.preventDefault();
                else if (key !== KEY_ENTER)
                    this._toggleElementSelectedClass(true)
            },
            _handleInputKeyUp: function(e) {
                var key = e.which;
                this._caretPosition = {
                    start: this._input().prop("selectionStart"),
                    end: this._input().prop("selectionEnd")
                };
                switch (key) {
                    case KEY_DOWN:
                        this._handleInputDownKey();
                        break;
                    case KEY_UP:
                        this._handleInputUpKey();
                        break;
                    case KEY_ENTER:
                        this._handleInputEnterKey();
                        break;
                    case KEY_RIGHT:
                    case KEY_TAB:
                        this._handleInputCompleteKeys();
                        break;
                    case KEY_ESC:
                        this._hideDropDown();
                        break;
                    default:
                        return
                }
            },
            _handleInputDownKey: function() {
                var $selectedItem = this._listSelectedItemElement(),
                    $nextItem;
                if ($selectedItem.length) {
                    $nextItem = $selectedItem.next();
                    if ($nextItem.length)
                        $nextItem.addClass(this._getSelectedItemClass());
                    else
                        this._toggleElementSelectedClass(true);
                    $selectedItem.removeClass(this._getSelectedItemClass());
                    this._list.scrollToItem($nextItem)
                }
                else {
                    this._listItemElement().first().addClass(this._getSelectedItemClass());
                    this._list.scrollToItem(this._listItemElement().first());
                    this._toggleElementSelectedClass(false)
                }
            },
            _handleInputUpKey: function() {
                var $selectedItem = this._listSelectedItemElement(),
                    $prevItem,
                    $list = this._listElement();
                if ($list.is(":hidden"))
                    return;
                if (!$selectedItem.length) {
                    this._listItemElement().last().addClass(this._getSelectedItemClass());
                    this._list.scrollToItem(this._listItemElement().last());
                    this._toggleElementSelectedClass(false);
                    return
                }
                $selectedItem.removeClass(this._getSelectedItemClass());
                $prevItem = $selectedItem.prev();
                if ($prevItem.length) {
                    $prevItem.addClass(this._getSelectedItemClass());
                    this._list.scrollToItem($prevItem)
                }
                else
                    this._toggleElementSelectedClass(true)
            },
            _handleInputEnterKey: function() {
                var $selectedItem = this._listSelectedItemElement(),
                    receivedValue;
                if (!$selectedItem.length) {
                    this._hideDropDown();
                    return
                }
                receivedValue = this._selectedItemDataGetter();
                this._caretPosition = {
                    start: receivedValue.length,
                    end: receivedValue.length
                };
                this.option("value", receivedValue);
                this._hideDropDown();
                this._input().blur()
            },
            _handleInputCompleteKeys: function() {
                var $list = this._listElement(),
                    newValue,
                    receivedValue;
                if ($list.is(":hidden"))
                    return;
                receivedValue = this._selectedItemDataGetter();
                newValue = receivedValue.length ? receivedValue : this._dataSource.items()[0];
                this._caretPosition = {
                    start: newValue.length,
                    end: newValue.length
                };
                newValue = this._displayGetter(newValue);
                this.option("value", newValue);
                this._hideDropDown()
            },
            _toggleElementSelectedClass: function(isToggle) {
                this._element().toggleClass(this._getSelectedItemClass(), isToggle)
            },
            _selectedItemDataGetter: function() {
                var $selectedItem = this._listSelectedItemElement();
                return $selectedItem.length ? this._displayGetter($selectedItem.data(LIST_ITEM_DATA_KEY)) : []
            },
            _createDropDown: function() {
                var popupWidth = this.option("width"),
                    vOffset = 0,
                    hOffset = 0;
                if (DX.devices.current().win8)
                    vOffset = -6;
                else if (DX.devices.current().platform === "generic" || DX.devices.current().tizen)
                    vOffset = -1;
                this._dropDown = $("<div>").appendTo(this._element()).dxPopup({
                    rtlEnabled: this.option("rtlEnabled"),
                    shading: false,
                    closeOnOutsideClick: false,
                    closeOnTargetScroll: true,
                    showTitle: false,
                    width: popupWidth,
                    showingAction: $.proxy(this._dimensionChanged, this),
                    deferRendering: false,
                    shownAction: this.option("openAction"),
                    hiddenAction: this.option("closeAction"),
                    position: {
                        my: "left top",
                        at: "left bottom",
                        of: this._$element,
                        offset: {
                            h: hOffset,
                            v: vOffset
                        },
                        collision: "flip"
                    },
                    animation: {
                        show: {
                            type: "pop",
                            duration: 400,
                            from: {
                                opacity: 0,
                                scale: 1
                            },
                            to: {
                                opacity: 1,
                                scale: 1
                            }
                        },
                        hide: {
                            type: "fade",
                            duration: 400,
                            from: 1,
                            to: 0
                        }
                    }
                }).dxPopup("instance");
                this._dropDown._wrapper().addClass(AUTOCOMPLETE_POPUP_WRAPPER_CLASS);
                this._renderList()
            },
            _dimensionChanged: function() {
                this._calculatePopupDimensions()
            },
            _calculatePopupDimensions: function() {
                this._calculatePopupHeight();
                this._calculatePopupWidth()
            },
            _calculatePopupHeight: function() {
                var popup = this._dropDown;
                popup.option("height", "auto");
                var list = this._list;
                this._heightApplyingTimer = setTimeout(function() {
                    var popupHeight = popup.container().outerHeight();
                    var maxHeight = $(window).height() * 0.5;
                    popup.option("height", Math.min(popupHeight, maxHeight));
                    list.updateDimensions()
                })
            },
            _calculatePopupWidth: function() {
                var textWidth = this._element().outerWidth();
                this._dropDown.option("width", textWidth)
            },
            _getSelectedItemClass: function() {
                return SELECTED_ITEM_CLASS
            },
            _getSelectedItemSelector: function() {
                return SELECTED_ITEM_SELECTOR
            },
            _renderList: function() {
                this._list = $("<div>").appendTo(this._dropDown.content()).dxList({
                    itemClickAction: $.proxy(this._handleListItemClick, this),
                    itemTemplate: this._getTemplateByOption("itemTemplate"),
                    itemRender: this._getItemRender(),
                    noDataText: "",
                    showNextButton: false,
                    autoPagingEnabled: false,
                    dataSource: this._dataSource,
                    indicateLoading: false
                }).dxList("instance")
            },
            _getItemRender: function() {
                if (!this.option("itemTemplate"))
                    return this.option("itemRender") || $.proxy(this._displayGetter, this)
            },
            _handleListItemClick: function(e) {
                var value = this._displayGetter(e.itemData);
                this._caretPosition = {
                    start: value.length,
                    end: value.length
                };
                this.option("value", value);
                this._hideDropDown();
                this._input().blur()
            },
            _itemsToDataSource: function() {
                this._dataSource = new DevExpress.data.DataSource(this.option("items"));
                return this._dataSource
            },
            _filterDataSource: function() {
                this._reloadDataSource(this.option("value"));
                this._clearSearchTimer()
            },
            _reloadDataSource: function(searchValue, searchMethod) {
                var that = this,
                    ds = that._dataSource;
                ds.searchExpr(that.option("displayExpr"));
                ds.searchOperation(searchMethod || that.option("searchMode"));
                ds.searchValue(searchValue);
                that._dataSource.pageIndex(0);
                that._dataSource.load().done(function() {
                    that._refreshVisibility()
                })
            },
            _refreshVisibility: function() {
                var canFilter = this.option("value").length >= this.option("minSearchLength"),
                    dataSource = this._dataSource,
                    items = dataSource && dataSource.items(),
                    hasResults = items.length;
                if (canFilter && hasResults)
                    if (items.length === 1 && this._displayGetter(items[0]) === this.option("value"))
                        this._hideDropDown();
                    else if (this._displayGetter(items[0]).length < this.option("value").length)
                        this._hideDropDown();
                    else {
                        this._dropDown._refresh();
                        this._dropDown.show();
                        this._calculatePopupHeight()
                    }
                else
                    this._hideDropDown()
            },
            _closeOutsideDropDownHandler: function(e, ignoreContainerClicks) {
                this.callBase(e, true)
            },
            _clean: function() {
                this.callBase();
                delete this._dropDown
            },
            _dispose: function() {
                clearTimeout(this._heightApplyingTimer);
                this._clearSearchTimer();
                this.callBase()
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"items":
                    case"dataSource":
                        if (name === "items")
                            this._itemsToDataSource();
                        else
                            this._initDataSource();
                    case"itemTemplate":
                    case"itemRender":
                        this._list.option(name, value);
                        break;
                    case"searchMode":
                        this._validateSearchMode();
                        break;
                    case"displayExpr":
                        this._compileDisplayGetter();
                        this._list.option("itemRender", this._getItemRender());
                        break;
                    case"minSearchLength":
                    case"searchTimeout":
                        break;
                    case"shouldActivateFocusOut":
                        this._invalidate();
                        break;
                    case"value":
                        this._applyFilter();
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _applyFilter: function() {
                var canFilter = this.option("value").length >= this.option("minSearchLength");
                if (!canFilter) {
                    this._clearSearchTimer();
                    this._hideDropDown();
                    return
                }
                if (this.option("searchTimeout") > 0) {
                    if (!this._searchTimer)
                        this._searchTimer = setTimeout($.proxy(this._filterDataSource, this), this.option("searchTimeout"))
                }
                else
                    this._filterDataSource()
            },
            _clearSearchTimer: function() {
                clearTimeout(this._searchTimer);
                delete this._searchTimer
            }
        }).include(ui.DataHelperMixin))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.selectBox.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            WIDGET_CLASS = "dx-selectbox",
            POPUP_CLASS = "dx-selectbox-popup",
            SELECTBOX_SELECTED_CLASS = "dx-selectbox-selected",
            SELECTBOX_MULTISELECT_CLASS = "dx-selectbox-multiselect",
            SELECTBOX_CONTAINER_CLASS = "dx-selectbox-container",
            SELECTBOX_ARROW_CLASS = "dx-selectbox-arrow",
            SELECTBOX_ARROW_CONTAINER_CLASS = "dx-selectbox-arrow-container",
            SELECTBOX_TAG_CONTAINER_CLASS = "dx-selectbox-tag-container",
            SELECTBOX_TAG_ITEM_CLASS = "dx-selectbox-tag-item",
            SELECTBOX_TAG_ITEM_CONTAINER_CLASS = "dx-selectbox-tag-item-container",
            SELECTBOX_TAG_ITEM_CLOSE_BUTTON_CLASS = "dx-selectbox-tag-item-close-button",
            EMPTY_INPUT_CLASS = "dx-texteditor-empty",
            LIST_ITEM_DATA_KEY = "dxListItemData",
            LIST_ITEM_SELECTOR = ".dx-list-item",
            TEXTEDITOR_BORDER_SELECTOR = ".dx-texteditor-border";
        DX.registerComponent("dxSelectBox", ui.dxAutocomplete.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    items: [],
                    value: undefined,
                    valueChangeAction: null,
                    placeholder: Globalize.localize("Select"),
                    valueExpr: null,
                    multiSelectEnabled: false,
                    values: [],
                    fieldTemplate: null,
                    displayValue: undefined,
                    tooltipEnabled: false,
                    shouldActivateFocusOut: false
                })
            },
            _optionsByReference: function() {
                return $.extend(this.callBase(), {value: true})
            },
            _init: function() {
                this.callBase();
                if (!this._dataSource)
                    this._itemsToDataSource()
            },
            _itemsToDataSource: function() {
                this._dataSource = new DevExpress.data.DataSource(this.option("items"))
            },
            _getValueWidth: function(value) {
                var $div = $("<div>").html(value).css({
                        width: "auto",
                        position: "fixed",
                        top: "-3000px",
                        left: "-3000px"
                    }).appendTo("body");
                return $div.width()
            },
            _setTooltip: function(value) {
                if (!this.option("tooltipEnabled"))
                    return;
                if (this._$element.context.scrollWidth <= this._getValueWidth(value))
                    this._$element.context.title = value;
                else
                    this._$element.context.title = ""
            },
            _render: function() {
                this._compileValueGetter();
                this.callBase();
                var value = this.option("value");
                if (value)
                    this._searchValue(value).done($.proxy(this._updateTextBox, this));
                else
                    this._updateTextBox();
                var multiSelectEnabled = this.option("multiSelectEnabled");
                this._element().toggleClass(SELECTBOX_MULTISELECT_CLASS, multiSelectEnabled);
                if (multiSelectEnabled)
                    this._renderTags();
                this._setWidgetClasses();
                this._setTooltip(this.option("value"));
                this._shouldHide = false
            },
            _renderTags: function() {
                if (this._$tagContainer)
                    this._$tagContainer.remove();
                this._$tagContainer = $("<div>").addClass(SELECTBOX_TAG_CONTAINER_CLASS);
                var values = this.option("values") || [],
                    clickEventName = events.addNamespace("dxclick", this.NAME),
                    that = this;
                $.each(values, function(index, value) {
                    var displayValue;
                    that._searchValue(value).done($.proxy(function(result) {
                        displayValue = that._displayGetter(result)
                    }, that));
                    var $container = $("<div>").addClass(SELECTBOX_TAG_ITEM_CONTAINER_CLASS),
                        $tag = $("<div>").append(displayValue).addClass(SELECTBOX_TAG_ITEM_CLASS).appendTo($container),
                        $close = $("<div>").addClass(SELECTBOX_TAG_ITEM_CLOSE_BUTTON_CLASS).appendTo($container);
                    $close.off(clickEventName).on(clickEventName, $.proxy(that._deleteTag, that));
                    $container.appendTo(that._$tagContainer)
                });
                this._$tagContainer.appendTo(this._$container);
                this._element().toggleClass(EMPTY_INPUT_CLASS, !values.length);
                this._input().val(values.length ? " " : null)
            },
            _deleteTag: function(event) {
                event.stopPropagation();
                var $item = $(event.currentTarget.parentElement),
                    index = $item.index(),
                    values = this.option("values");
                this.option().value = this.option("values")[index];
                values.splice(index, 1);
                this.option("values", values)
            },
            _renderInput: function(inputContainer) {
                this._$container = inputContainer || $("<div>");
                this._$container.addClass(SELECTBOX_CONTAINER_CLASS);
                this._element().append(this._$container);
                this.callBase(this._$container);
                this._renderInputTemplate()
            },
            _renderInputTemplate: function() {
                var fieldTemplate = this._getTemplateByOption("fieldTemplate");
                if (this.option("fieldTemplate") && fieldTemplate) {
                    this._$container.empty();
                    var templateData = this.option("multiSelectEnabled") ? this.option("values") : this.option("value");
                    fieldTemplate.render(this._$container, templateData);
                    if (!this._input().length)
                        DX.utils.logger.warn("A template should contain dxTextBox widget")
                }
            },
            _handleValueChangeEvent: function(e) {
                var args = [e];
                if (!this._input().val())
                    args.push(undefined);
                this.callBase.apply(this, args)
            },
            _renderButton: function(hideButton) {
                this.callBase(false)
            },
            _renderValue: function(formattedValue) {
                if (this.option("value") !== undefined) {
                    var callBase = $.proxy(this.callBase, this);
                    this._searchValue(this.option("value")).done($.proxy(function(result) {
                        if (result === undefined)
                            result = this.option("value");
                        this._selectedItem = result;
                        this.option("displayValue", this._displayGetter(result));
                        this._setTooltip(result);
                        callBase(this._displayGetter(result))
                    }, this))
                }
                else {
                    this._selectedItem = null;
                    this.option("displayValue", null);
                    this._setTooltip(null);
                    this.callBase(null)
                }
            },
            _readOnlyPropValue: function() {
                return true
            },
            _createDropDown: function() {
                var that = this;
                this.callBase();
                this._dropDown.beginUpdate();
                if (DX.devices.current().win8) {
                    var popupPosition = this._dropDown.option("position");
                    $.extend(popupPosition, {
                        at: "left top",
                        offset: {
                            h: 0,
                            v: 0
                        }
                    });
                    this._dropDown.option("position", popupPosition)
                }
                this._dropDown.option("closeOnOutsideClick", $.proxy(this._closeOutsideDropDownHandler, this));
                this._dropDown.endUpdate()
            },
            _setWidgetClasses: function() {
                var $selectbox = this._element(),
                    $popup = this._dropDown._element();
                $selectbox.addClass(WIDGET_CLASS);
                $popup.addClass(POPUP_CLASS)
            },
            _pointerDownHandler: function() {
                if (this._dropDown.option("visible"))
                    this._shouldHide = true
            },
            _clickHandler: function() {
                if (!this._dropDown.option("visible") && !this._shouldHide)
                    this._showDropDown();
                else
                    this._shouldHide = false
            },
            _applyFilter: $.noop,
            _updateTextBox: function(result) {
                var that = this,
                    clickEventName = events.addNamespace("dxclick", this.NAME),
                    pointerDownEventName = events.addNamespace("dxpointerdown", this.NAME);
                this._clickAction = this._createAction(function() {
                    that._clickHandler()
                });
                this._selectedItem = result;
                this._$container.off(clickEventName).off(pointerDownEventName).on(clickEventName, function() {
                    that._clickAction()
                }).on(pointerDownEventName, $.proxy(this._pointerDownHandler, this))
            },
            _compileValueGetter: function() {
                this._valueGetter = DX.data.utils.compileGetter(this._valueGetterExpr())
            },
            _valueGetterExpr: function() {
                return this.option("valueExpr") || this._dataSource && this._dataSource._store._key || "this"
            },
            _setSelectedClass: function(item, itemData) {
                itemData = itemData;
                if (this.option("multiSelectEnabled"))
                    $.each(this._getSelected(), function() {
                        $(this).addClass(SELECTBOX_SELECTED_CLASS)
                    });
                else {
                    item = item || this._getSelected();
                    if (item === null)
                        return;
                    var selected = itemData !== undefined ? this._optionValuesEqual("value", this._valueGetter(itemData), this.option("value")) : true;
                    item.toggleClass(SELECTBOX_SELECTED_CLASS, selected)
                }
            },
            _getSelected: function() {
                var items = [],
                    listElement = this._list._element(),
                    values = this.option("multiSelectEnabled") ? this.option("values") : [this.option("value")],
                    valueGetter = this._valueGetter;
                $.each(this._list.option("items"), function(index, val) {
                    if ($.inArray(valueGetter(val), values) !== -1)
                        items.push(listElement.find(LIST_ITEM_SELECTOR).eq(index))
                });
                if (!this.option("multiSelectEnabled"))
                    return items[0] || null;
                return items
            },
            _removeSelectedClass: function() {
                this._list._element().find("." + SELECTBOX_SELECTED_CLASS).removeClass(SELECTBOX_SELECTED_CLASS)
            },
            _updateSelectedItems: function(item, itemData) {
                this._removeSelectedClass();
                this._setSelectedClass(item, itemData)
            },
            _handleListItemClick: function(e) {
                this._hideDropDown();
                this._shouldHide = false;
                if (this.option("multiSelectEnabled")) {
                    this.option().value = this._valueGetter(e.itemData);
                    this._addTagValue(this.option("value"))
                }
                else
                    this.option("value", this._valueGetter(e.itemData))
            },
            _handleInputEnterKey: function() {
                this.callBase();
                if (this.option("multiSelectEnabled"))
                    this._addTagValue(this.option("value"))
            },
            _selectedItemDataGetter: function() {
                var $selectedItem = this._listSelectedItemElement();
                return $selectedItem.length ? this._valueGetter($selectedItem.data(LIST_ITEM_DATA_KEY)) : []
            },
            _addTagValue: function(value) {
                var values = this.option("values") || [],
                    newValues = [];
                if ($.inArray(value, values) === -1) {
                    newValues.push.apply(newValues, values);
                    newValues.push(value);
                    this.option("values", newValues)
                }
            },
            _searchValue: function(value) {
                var that = this,
                    store = this._dataSource.store(),
                    valueExpr = this._valueGetterExpr();
                var deffered = $.Deferred();
                if (valueExpr === store.key() || store instanceof DX.data.CustomStore)
                    store.byKey(value).done(function(result) {
                        deffered.resolveWith(that, [result])
                    });
                else
                    store.load({filter: [valueExpr, value]}).done(function(result) {
                        deffered.resolveWith(that, result)
                    });
                return deffered.promise()
            },
            _changeValueExpr: function() {
                this._compileValueGetter();
                this.option("value", this._valueGetter(this._selectedItem))
            },
            _getSelectedItemClass: function() {
                return SELECTBOX_SELECTED_CLASS
            },
            _getSelectedItemSelector: function() {
                return "." + SELECTBOX_SELECTED_CLASS
            },
            _renderList: function() {
                this.callBase();
                this._list.option({
                    autoPagingEnabled: true,
                    itemRenderedAction: $.proxy(function(e) {
                        this._setSelectedClass(e.itemElement, e.itemData)
                    }, this)
                })
            },
            _hideOnBlur: function() {
                return false
            },
            _handleClearValue: function() {
                if (this.option("multiSelectEnabled"))
                    this.option("values", []);
                this.option("value", null)
            },
            _optionChanged: function(name, value, previousValue) {
                switch (name) {
                    case"value":
                        this.callBase.apply(this, arguments);
                        this._updateSelectedItems();
                        this._renderInputTemplate();
                        break;
                    case"displayValue":
                        break;
                    case"tooltipEnabled":
                        this._setTooltip(this.option("value"));
                        break;
                    case"valueExpr":
                        this._changeValueExpr();
                        break;
                    case"displayExpr":
                        this._compileDisplayGetter();
                        this._refresh();
                        break;
                    case"fieldTemplate":
                        this._renderInputTemplate();
                        break;
                    case"values":
                        if (this.option("multiSelectEnabled")) {
                            this._renderTags();
                            this._updateSelectedItems();
                            this._raiseValueChangeAction(this.option("value"), previousValue, {values: value})
                        }
                        break;
                    case"multiSelectEnabled":
                        this._refresh();
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-base, file ui.multiView.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils,
            fx = DX.fx,
            translator = DX.translator;
        var MULTIVIEW_CLASS = "dx-multiview",
            MULTIVIEW_WRAPPER_CLASS = "dx-multiview-wrapper",
            MULTIVIEW_ITEM_CONTAINER_CLASS = "dx-multiview-item-container",
            MULTIVIEW_ITEM_CLASS = "dx-multiview-item",
            MULTIVIEW_ITEM_HIDDEN_CLASS = "dx-multiview-item-hidden",
            MULTIVIEW_ITEM_DATA_KEY = "dxMultiViewItemData";
        var position = function($element) {
                return translator.locate($element).left
            };
        var move = function($element, position) {
                translator.move($element, {left: position})
            };
        var animation = {
                moveTo: function($element, position, completeAction) {
                    fx.animate($element, {
                        type: "slide",
                        to: {left: position},
                        duration: 200,
                        complete: completeAction
                    })
                },
                complete: function($element) {
                    fx.stop($element, true)
                }
            };
        DX.registerComponent("dxMultiView", ui.CollectionContainerWidget.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    selectedIndex: 0,
                    swipeEnabled: true,
                    animationEnabled: true,
                    loop: false
                })
            },
            _itemClass: function() {
                return MULTIVIEW_ITEM_CLASS
            },
            _itemDataKey: function() {
                return MULTIVIEW_ITEM_DATA_KEY
            },
            _itemContainer: function() {
                return this._$itemContainer
            },
            _selectionByClickEnabled: function() {
                return false
            },
            _itemWidth: function() {
                if (!this._itemWidthValue)
                    this._itemWidthValue = this._$wrapper.width();
                return this._itemWidthValue
            },
            _clearItemWidthCache: function() {
                delete this._itemWidthValue
            },
            _itemsCount: function() {
                return this.option("items").length
            },
            _normalizeIndex: function(index) {
                var count = this._itemsCount();
                if (index < 0)
                    index = index + count;
                if (index >= count)
                    index = index - count;
                return index
            },
            _init: function() {
                this.callBase.apply(this, arguments);
                var $element = this._element();
                $element.addClass(MULTIVIEW_CLASS);
                this._$wrapper = $("<div>").addClass(MULTIVIEW_WRAPPER_CLASS);
                this._$wrapper.appendTo($element);
                this._$itemContainer = $("<div>").addClass(MULTIVIEW_ITEM_CONTAINER_CLASS);
                this._$itemContainer.appendTo(this._$wrapper);
                this._initSwipeable()
            },
            _dimensionChanged: function() {
                this._clearItemWidthCache()
            },
            _renderSelectedIndex: function(selectedIndex) {
                this._updateItems(selectedIndex)
            },
            _updateItems: function(selectedIndex, newIndex) {
                this._updateItemsPosition(selectedIndex, newIndex);
                this._updateItemsVisibility(selectedIndex, newIndex)
            },
            _updateItemsVisibility: function(selectedIndex, newIndex) {
                var $itemElements = this._itemElements();
                $itemElements.each(function(itemIndex, item) {
                    var $item = $(item),
                        isHidden = itemIndex !== selectedIndex && itemIndex !== newIndex;
                    $item.toggleClass(MULTIVIEW_ITEM_HIDDEN_CLASS, isHidden)
                })
            },
            _updateItemsPosition: function(selectedIndex, newIndex) {
                var $itemElements = this._itemElements(),
                    positionSign = -this._animationDirection(newIndex, selectedIndex);
                move($itemElements.eq(selectedIndex), 0);
                move($itemElements.eq(newIndex), positionSign * 100 + "%")
            },
            _updateSelectedIndex: function(newIndex, prevIndex) {
                animation.complete(this._$itemContainter);
                this._updateItems(prevIndex, newIndex);
                var animationDirection = this._animationDirection(newIndex, prevIndex);
                this._animateItemContainer(animationDirection * this._itemWidth(), $.proxy(function() {
                    move(this._$itemContainer, 0);
                    this._updateItems(newIndex)
                }, this))
            },
            _animateItemContainer: function(position, completeCallback) {
                if (this.option("animationEnabled"))
                    animation.moveTo(this._$itemContainer, position, completeCallback);
                else
                    completeCallback()
            },
            _animationDirection: function(newIndex, prevIndex) {
                var containerPosition = position(this._$itemContainer),
                    indexDifference = (prevIndex - newIndex) * this._getRTLSignCorrection(),
                    isSwipePresent = containerPosition !== 0,
                    directionSignVariable = isSwipePresent ? containerPosition : indexDifference;
                return utils.sign(directionSignVariable)
            },
            _initSwipeable: function() {
                this._element().dxSwipeable({
                    elastic: false,
                    itemSizeFunc: $.proxy(this._itemWidth, this),
                    startAction: $.proxy(function(args) {
                        this._handleSwipeStart(args.jQueryEvent)
                    }, this),
                    updateAction: $.proxy(function(args) {
                        this._handleSwipeUpdate(args.jQueryEvent)
                    }, this),
                    endAction: $.proxy(function(args) {
                        this._handleSwipeEnd(args.jQueryEvent)
                    }, this)
                })
            },
            _handleSwipeStart: function(e) {
                animation.complete(this._$itemContainer);
                if (!this.option("swipeEnabled"))
                    e.cancel = true;
                var selectedIndex = this.option("selectedIndex"),
                    loop = this.option("loop"),
                    lastIndex = this._itemsCount() - 1,
                    rtl = this.option("rtlEnabled");
                e.maxLeftOffset = loop || (rtl ? selectedIndex > 0 : selectedIndex < lastIndex);
                e.maxRightOffset = loop || (rtl ? selectedIndex < lastIndex : selectedIndex > 0)
            },
            _handleSwipeUpdate: function(e) {
                var offset = e.offset,
                    swipeDirection = utils.sign(offset) * this._getRTLSignCorrection();
                move(this._$itemContainer, offset * 100 + "%");
                if (swipeDirection !== this._swipeDirection) {
                    this._swipeDirection = swipeDirection;
                    var selectedIndex = this.option("selectedIndex"),
                        newIndex = this._normalizeIndex(selectedIndex - swipeDirection);
                    this._updateItems(selectedIndex, newIndex)
                }
            },
            _handleSwipeEnd: function(e) {
                var targetOffset = e.targetOffset * this._getRTLSignCorrection();
                if (targetOffset)
                    this.option("selectedIndex", this._normalizeIndex(this.option("selectedIndex") - targetOffset));
                else
                    this._animateItemContainer(0, $.noop);
                delete this._swipeDirection
            },
            _getRTLSignCorrection: function() {
                return this.option("rtlEnabled") ? -1 : 1
            },
            _visibilityChanged: function(visible) {
                if (visible)
                    this._clearItemWidthCache()
            },
            _optionChanged: function(name, value, prevValue) {
                switch (name) {
                    case"loop":
                    case"swipeEnabled":
                    case"animationEnabled":
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            }
        }));
        ui.dxMultiView.__internals = {animation: animation}
    })(jQuery, DevExpress);
    DevExpress.MOD_WIDGETS_BASE = true
}
if (!DevExpress.MOD_WIDGETS_WEB) {
    if (!DevExpress.MOD_WIDGETS_BASE)
        throw Error('Required module is not referenced: widgets-base');
    /*! Module widgets-web, file ui.pager.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            Class = DX.Class;
        var PAGES_LIMITER = 4,
            PAGER_CLASS = 'dx-pager',
            PAGER_PAGE_CLASS = 'dx-page',
            PAGER_PAGES_CLASS = 'dx-pages',
            PAGER_SELECTION_CLASS = 'dx-selection',
            PAGER_PAGE_SEPARATOR_CLASS = 'dx-separator',
            PAGER_PAGE_SIZES_CLASS = 'dx-page-sizes',
            PAGER_PAGE_SIZE_CLASS = 'dx-page-size';
        var Page = Class.inherit({
                ctor: function(value, index) {
                    var that = this;
                    that.index = index;
                    that.element = $('<div />').text(value).addClass(PAGER_PAGE_CLASS)
                },
                value: function(value) {
                    var that = this;
                    if (utils.isDefined(value))
                        that.element.text(value);
                    else {
                        var text = that.element.text();
                        if (utils.isNumber(text))
                            return parseInt(text);
                        else
                            return text
                    }
                },
                select: function(value) {
                    this.element.toggleClass(PAGER_SELECTION_CLASS, value)
                },
                render: function(rootElement, rtlEnabled) {
                    rtlEnabled ? this.element.prependTo(rootElement) : this.element.appendTo(rootElement)
                }
            });
        DX.registerComponent("dxPager", DX.DOMComponent.inherit({
            NAMESPACE: ui,
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    visible: true,
                    pageIndex: 1,
                    maxPagesCount: 10,
                    pagesCount: 10,
                    pageSize: 5,
                    showPageSizes: true,
                    pageSizes: [5, 10],
                    hasKnownLastPage: true,
                    pageIndexChanged: $.noop,
                    pageSizeChanged: $.noop
                })
            },
            _toggleVisibility: function(value) {
                var $element = this._element();
                if ($element)
                    $element.css("display", value ? "" : "none")
            },
            _getPages: function(currentPage, count) {
                var pages = [],
                    showMoreButton = !this.option("hasKnownLastPage"),
                    firstValue,
                    i;
                this._testPagesCount = count;
                this._testShowMoreButton = showMoreButton;
                if (count > 1 || showMoreButton)
                    if (count <= this.option("maxPagesCount")) {
                        for (i = 1; i <= count; i++)
                            pages.push(new Page(i, i - 1));
                        if (showMoreButton)
                            pages.push(new Page('>', i - 1))
                    }
                    else {
                        pages.push(new Page(1, 0));
                        firstValue = currentPage ? currentPage.value() - currentPage.index : 1;
                        for (i = 1; i <= PAGES_LIMITER; i++)
                            pages.push(new Page(firstValue + i, i));
                        pages.push(new Page(count, PAGES_LIMITER + 1));
                        if (showMoreButton)
                            pages.push(new Page('>', PAGES_LIMITER + 1))
                    }
                return pages
            },
            _getPageByValue: function(value) {
                var that = this,
                    page,
                    i;
                for (i = 0; i < that._pages.length; i++) {
                    page = that._pages[i];
                    if (page.value() === value)
                        return page
                }
            },
            _processSelectedPage: function(maxPagesCount, pageIndex, pagesCount) {
                var that = this,
                    isPageIndexValid = false,
                    selectedPageIndex;
                if (that._pages) {
                    $.each(that._pages, function(key, page) {
                        if (pageIndex === page.value())
                            isPageIndexValid = true
                    });
                    if (!isPageIndexValid)
                        that.selectedPage = null
                }
                if (utils.isDefined(that.selectedPage)) {
                    if (pageIndex === pagesCount && pagesCount > maxPagesCount && that.selectedPage.index !== PAGES_LIMITER + 1)
                        that.selectedPage.index = PAGES_LIMITER + 1
                }
                else if (pageIndex > PAGES_LIMITER && pageIndex < pagesCount) {
                    selectedPageIndex = pagesCount - PAGES_LIMITER < pageIndex ? PAGES_LIMITER - (pagesCount - pageIndex) + 1 : 2;
                    that.selectedPage = new Page(pageIndex, selectedPageIndex)
                }
            },
            _selectPageByValue: function(value) {
                var that = this,
                    i,
                    page = that._getPageByValue(value),
                    pages = that._pages,
                    pagesLength = pages.length,
                    prevPage,
                    nextPage,
                    morePage;
                if (!utils.isDefined(page))
                    return;
                prevPage = that._pages[page.index - 1];
                nextPage = that._pages[page.index + 1];
                if (nextPage && nextPage.value() === '>') {
                    morePage = nextPage;
                    nextPage = undefined;
                    pagesLength--;
                    pages.pop()
                }
                if (that.selectedPage)
                    that.selectedPage.select(false);
                page.select(true);
                that.selectedPage = page;
                if (nextPage && nextPage.value() - value > 1)
                    if (page.index !== 0) {
                        prevPage.value(value + 1);
                        that._pages.splice(page.index, 1);
                        that._pages.splice(page.index - 1, 0, page);
                        that._pages[page.index].index = page.index;
                        page.index = page.index - 1;
                        for (i = page.index - 1; i > 0; i--)
                            that._pages[i].value(that._pages[i + 1].value() - 1)
                    }
                    else
                        for (i = 0; i < pagesLength - 1; i++)
                            that._pages[i].value(i + 1);
                if (prevPage && value - prevPage.value() > 1)
                    if (page.index !== pagesLength - 1) {
                        nextPage.value(value - 1);
                        that._pages.splice(page.index, 1);
                        that._pages.splice(page.index + 1, 0, page);
                        that._pages[page.index].index = page.index;
                        page.index = page.index + 1;
                        for (i = page.index + 1; i < pagesLength - 1; i++)
                            that._pages[i].value(that._pages[i - 1].value() + 1)
                    }
                    else
                        for (i = 1; i <= pagesLength - 2; i++)
                            that._pages[pagesLength - 1 - i].value(that._pages[pagesLength - 1].value() - i);
                if (morePage)
                    pages.push(morePage)
            },
            _renderPagesChooser: function() {
                var that = this,
                    page,
                    pageIndexChanged = that.option("pageIndexChanged"),
                    i,
                    $element = that._element();
                if (!$element)
                    return;
                that._clickPagesIndexAction = that._createAction(function(args) {
                    var e = args.jQueryEvent,
                        pageNumber = $(e.target).text(),
                        pageIndex = pageNumber === '>' ? that.option("pagesCount") + 1 : Number(pageNumber);
                    that._testPageIndex = pageIndex;
                    that.option("pageIndex", pageIndex);
                    pageIndexChanged(pageIndex)
                });
                if (utils.isDefined(that.pagesChooserElement))
                    that.pagesChooserElement.empty();
                else
                    that.pagesChooserElement = $('<div />').addClass(PAGER_PAGES_CLASS).on(events.addNamespace("dxclick", that.Name + "Pages"), '.' + PAGER_PAGE_CLASS, function(e) {
                        that._clickPagesIndexAction({jQueryEvent: e})
                    });
                if (that._pages.length === 0) {
                    that.selectedPage = null;
                    return
                }
                for (i = 0; i < that._pages.length; i++) {
                    page = that._pages[i];
                    page.render(that.pagesChooserElement, that.option('rtlEnabled'));
                    if (that._pages[i + 1] && that._pages[i + 1].value() - page.value() > 1) {
                        var $separator = $('<div>. . .</div>').addClass(PAGER_PAGE_SEPARATOR_CLASS).attr('style', '-webkit-user-select: none');
                        that.option('rtlEnabled') ? $separator.prependTo(that.pagesChooserElement) : $separator.appendTo(that.pagesChooserElement)
                    }
                }
                if (!utils.isDefined(that.pagesChooserElement[0].parentElement))
                    that.pagesChooserElement.appendTo($element)
            },
            _renderPagesSizeChooser: function() {
                var that = this,
                    i,
                    pageSizeElement,
                    currentPageSize = that.option("pageSize"),
                    pageSizes = that.option("pageSizes"),
                    showPageSizes = that.option("showPageSizes"),
                    pageSizeChanged = that.option("pageSizeChanged"),
                    pageSizeValue,
                    pagesSizesLength = pageSizes && pageSizes.length,
                    $element = that._element();
                if (!$element)
                    return;
                that._clickPagesSizeAction = that._createAction(function(args) {
                    var e = args.jQueryEvent;
                    pageSizeValue = parseInt($(e.target).text());
                    that._testPageSizeIndex = pageSizeValue;
                    that.option("pageSize", pageSizeValue);
                    pageSizeChanged(pageSizeValue)
                });
                if (utils.isDefined(that.pagesSizeChooserElement))
                    that.pagesSizeChooserElement.empty();
                else
                    that.pagesSizeChooserElement = $('<div />').addClass(PAGER_PAGE_SIZES_CLASS).on(events.addNamespace("dxclick", that.Name + "PageSize"), '.' + PAGER_PAGE_SIZE_CLASS, function(e) {
                        that._clickPagesSizeAction({jQueryEvent: e})
                    });
                if (!showPageSizes || !pagesSizesLength)
                    return;
                that._testCurrentPageSize = currentPageSize;
                for (i = 0; i < pagesSizesLength; i++) {
                    pageSizeElement = $('<div />').text(pageSizes[i]).addClass(PAGER_PAGE_SIZE_CLASS);
                    if (currentPageSize === pageSizes[i])
                        pageSizeElement.addClass(PAGER_SELECTION_CLASS);
                    that.option('rtlEnabled') ? that.pagesSizeChooserElement.prepend(pageSizeElement) : that.pagesSizeChooserElement.append(pageSizeElement)
                }
                if (!utils.isDefined(that.pagesSizeChooserElement[0].parentElement))
                    that.pagesSizeChooserElement.appendTo($element)
            },
            _render: function() {
                this._update();
                this._element().addClass(PAGER_CLASS);
                this._toggleVisibility(this.option("visible"));
                this._renderPagesSizeChooser();
                this._renderPagesChooser()
            },
            _update: function() {
                var pagesCount = this.option("pagesCount"),
                    pageIndex = this.option("pageIndex");
                this._processSelectedPage(this.option("maxPagesCount"), pageIndex, pagesCount);
                this._pages = this._getPages(this.selectedPage, pagesCount);
                this._selectPageByValue(pageIndex)
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"visible":
                        this._toggleVisibility(value);
                        break;
                    case"pageIndex":
                    case"maxPagesCount":
                    case"pagesCount":
                    case"hasKnownLastPage":
                        this._update();
                        this._renderPagesChooser();
                        break;
                    case"pageSize":
                    case"pageSizes":
                        this._renderPagesSizeChooser();
                        break;
                    default:
                        this._invalidate()
                }
            },
            getHeight: function() {
                return this.option("visible") ? this._element().outerHeight() : 0
            }
        }));
        ui.dxPager.__internals = {
            PAGER_CLASS: PAGER_CLASS,
            PAGER_PAGE_CLASS: PAGER_PAGE_CLASS,
            PAGER_PAGES_CLASS: PAGER_PAGES_CLASS,
            PAGER_SELECTION_CLASS: PAGER_SELECTION_CLASS,
            PAGER_PAGE_SEPARATOR_CLASS: PAGER_PAGE_SEPARATOR_CLASS,
            PAGER_PAGE_SIZES_CLASS: PAGER_PAGE_SIZES_CLASS,
            PAGER_PAGE_SIZE_CLASS: PAGER_PAGE_SIZE_CLASS
        }
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.colorPicker.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils;
        var COLOR_PICKER_CLASS = "dx-color-picker",
            COLOR_PICKER_INPUT_CONTAINER_CLASS = "dx-color-picker-input-container",
            COLOR_PICKER_INPUT_CLASS = "dx-color-picker-input",
            COLOR_PICKER_COLOR_RESULT_PREVIEW = "dx-color-picker-color-result-preview",
            COLOR_PICKER_OVERLAY_CLASS = "dx-color-picker-overlay",
            COLOR_PICKER_OVERLAY_WITHOUT_ALPHA_CHANNEL_CLASS = "dx-color-picker-without-alpha-channel",
            COLOR_PICKER_CONTAINER_CLASS = "dx-color-picker-container",
            COLOR_PICKER_ROW_CLASS = "dx-color-picker-container-row",
            COLOR_PICKER_CELL_CLASS = "dx-color-picker-container-cell",
            COLOR_PICKER_PALETTE_CLASS = "dx-color-picker-palette",
            COLOR_PICKER_PALETTE_GRADIENT_CLASS = "dx-color-picker-palette-gradient",
            COLOR_PICKER_PALETTE_GRADIENT_WHITE_CLASS = "dx-white",
            COLOR_PICKER_PALETTE_GRADIENT_BLACK_CLASS = "dx-black",
            COLOR_PICKER_HUE_SCALE_CLASS = "dx-color-picker-hue-scale",
            COLOR_PICKER_HUE_SCALE_HANDLE_CLASS = "dx-color-picker-hue-scale-handle",
            COLOR_PICKER_HUE_SCALE_WRAPPER_CLASS = "dx-hue-scale-wrapper",
            COLOR_PICKER_CONTROLS_CONTAINER_CLASS = "dx-color-picker-controls-container",
            COLOR_PICKER_BUTTONS_CONTAINER_CLASS = "dx-color-picker-buttons-container",
            COLOR_PICKER_APPLY_BUTTON_CLASS = "dx-color-picker-apply-button",
            COLOR_PICKER_CANCEL_BUTTON_CLASS = "dx-color-picker-cancel-button",
            COLOR_PICKER_COLOR_CHOOSER_CLASS = "dx-color-picker-color-chooser",
            COLOR_PICKER_RED_LABEL_CLASS = "dx-color-picker-red-label",
            COLOR_PICKER_GREEN_LABEL_CLASS = "dx-color-picker-green-label",
            COLOR_PICKER_BLUE_LABEL_CLASS = "dx-color-picker-blue-label",
            COLOR_PICKER_HEX_LABEL_CLASS = "dx-color-picker-hex-label",
            COLOR_PICKER_RED_INPUT_CLASS = "dx-color-picker-red-input",
            COLOR_PICKER_GREEN_INPUT_CLASS = "dx-color-picker-green-input",
            COLOR_PICKER_BLUE_INPUT_CLASS = "dx-color-picker-blue-input",
            COLOR_PICKER_HEX_INPUT_CLASS = "dx-color-picker-hex-input",
            COLOR_PICKER_ALPHA_CHANNEL_SCALE_WRAPPER_CLASS = "dx-color-picker-alpha-scale-wrapper",
            COLOR_PICKER_ALPHA_CHANNEL_SCALE_CLASS = "dx-color-picker-alpha-scale",
            COLOR_PICKER_ALPHA_CHANNEL_INPUT_CLASS = "dx-color-picker-alpha-input",
            COLOR_PICKER_ALPHA_CHANNEL_LABEL_CLASS = "dx-color-picker-alpha-label",
            COLOR_PICKER_ALPHA_CHANNEL_HANDLE_CLASS = "dx-color-picker-alpha-handle",
            COLOR_PICKER_ALPHA_CHANNEL_CELL_CLASS = "dx-alpha-channel-cell",
            COLOR_PICKER_ALPHA_CHANNEL_BORDER_CLASS = "dx-alpha-channel-border",
            COLOR_PICKER_COLOR_PREVIEW_CONTAINER_CLASS = "dx-color-picker-color-preview-container",
            COLOR_PICKER_COLOR_PREVIEW_CONTAINER_INNER_CLASS = "dx-color-picker-color-preview-container-inner",
            COLOR_PICKER_COLOR_PREVIEW = "dx-color-preview",
            COLOR_PICKER_CURRENT_COLOR_PREVIEW = "dx-current-color",
            COLOR_PICKER_NEW_COLOR_PREVIEW = "dx-new-color";
        $.fn.colorPickerDrag = function(options) {
            return this.each(function(i, el) {
                    var getCoordinatesFork = function() {
                            var Xmax,
                                Xmin,
                                Ymax,
                                Ymin;
                            var deltaX = parentWidth - halfOfElWidth,
                                deltaY = parentHeight - halfOfElHeight;
                            if (options.enableStripHalfOfWidth) {
                                Xmin = 0;
                                Xmax = parentWidth
                            }
                            else {
                                Xmin = halfOfElWidth;
                                Xmax = deltaX
                            }
                            if (options.enableStripHalfOfHeight) {
                                Ymin = 0;
                                Ymax = parentHeight
                            }
                            else {
                                Ymin = halfOfElHeight;
                                Ymax = deltaY
                            }
                            return {
                                    x: {
                                        min: Xmin,
                                        max: Xmax
                                    },
                                    y: {
                                        min: Ymin,
                                        max: Ymax
                                    }
                                }
                        };
                    var $base = $(el),
                        $parent = $base.parent(),
                        parentWidth = $parent.outerWidth(),
                        parentHeight = $parent.outerHeight(),
                        elHeight = $base.height(),
                        elWidth = $base.width(),
                        motionEnabled = false,
                        halfOfElHeight = elHeight / 2,
                        halfOfElWidth = elWidth / 2,
                        coordinates = getCoordinatesFork();
                    var defaultOptions = {
                            enableVerticalMotion: true,
                            enableHorizontalMotion: true,
                            moveByClick: true,
                            enableStripHalfOfWidth: false,
                            enableStripHalfOfHeight: false,
                            verticalMotionCallback: $.noop,
                            horizontalMotionCallback: $.noop,
                            _coordinatesUpdater: $.noop
                        };
                    options = $.extend(true, defaultOptions, options);
                    var moveElement = function(event) {
                            var x = options._coordinatesUpdater(event).x,
                                y = options._coordinatesUpdater(event).y;
                            changeElementPosition(x, y)
                        };
                    var changeElementPosition = function(x, y) {
                            if (options.enableVerticalMotion) {
                                if (y < coordinates.y.min)
                                    y = coordinates.y.min;
                                if (y > coordinates.y.max)
                                    y = coordinates.y.max;
                                $base.css("top", y - halfOfElHeight);
                                options.verticalMotionCallback(y)
                            }
                            if (options.enableHorizontalMotion) {
                                if (x < coordinates.x.min)
                                    x = coordinates.x.min;
                                if (x > coordinates.x.max)
                                    x = coordinates.x.max;
                                $base.css("right", "auto");
                                $base.css("left", x - halfOfElWidth);
                                options.horizontalMotionCallback(x)
                            }
                        };
                    if (!options._coordinatesUpdater)
                        options._coordinatesUpdater = function(event) {
                            return {
                                    x: event.pageX - $parent.offset().left,
                                    y: event.pageY - $parent.offset().top
                                }
                        };
                    $base.on(events.addNamespace("dxpointerdown", "dxColorPicker"), function() {
                        motionEnabled = true
                    });
                    $("*").on(events.addNamespace("dxpointerup", "dxColorPicker"), function() {
                        motionEnabled = false
                    });
                    $("body").on(events.addNamespace("dxpointermove", "dxColorPicker"), function(event) {
                        if (motionEnabled) {
                            event.preventDefault();
                            moveElement(event)
                        }
                    });
                    if (options.moveByClick)
                        $parent.on(events.addNamespace("dxpointerdown", "dxColorPicker"), function(event) {
                            motionEnabled = true;
                            moveElement(event)
                        })
                })
        };
        var htmlCreator = {
                createElement: function(tagName, cssClass, $parent) {
                    var el = document.createElement(tagName),
                        $el = $(el);
                    if (DX.utils.isArray(cssClass))
                        cssClass = cssClass.join(" ");
                    if (cssClass)
                        $el.addClass(cssClass);
                    if ($parent)
                        return $el.appendTo($parent);
                    else
                        return $el
                },
                createHtmlRows: function(count) {
                    var $rows = [];
                    for (var i = 0; i < count; i++)
                        $rows.push(this.createElement("div", COLOR_PICKER_ROW_CLASS));
                    return $rows
                },
                createHtmlCellInsideRow: function(rowIndex, $rowParent, additionalClass) {
                    var $row,
                        $rows = $rowParent.find("." + COLOR_PICKER_ROW_CLASS);
                    if (DX.utils.isNumber(rowIndex))
                        $row = $rows.eq(rowIndex);
                    else if (DX.utils.isString(rowIndex))
                        $row = $rows[rowIndex]();
                    var $cell = this.createElement("div", COLOR_PICKER_CELL_CLASS, $row);
                    if (additionalClass)
                        $cell.addClass(additionalClass);
                    return $cell
                },
                createInputWithLabel: function(labelText, labelClass, inputClass) {
                    return this.createElement("label", labelClass).text(labelText + ":").append(this.createElement("input", inputClass))
                }
            };
        var colorHelper = {makeCSSLinearGradient: function($el) {
                    var color = this._currentColor,
                        colorAsRgb = [color.r, color.g, color.b].join(","),
                        colorAsHex = color.toHex().replace("#", "");
                    var combineGradientString = function(colorAsRgb, colorAsHex) {
                            var rtlEnabled = this.option("rtlEnabled"),
                                startColor = "rgba(" + colorAsRgb + ", " + (rtlEnabled ? "1" : "0") + ")",
                                finishColor = "rgba(" + colorAsRgb + ", " + (rtlEnabled ? "0" : "1") + ")",
                                startColorIE = "'#" + (rtlEnabled ? "00" : "") + colorAsHex + "'",
                                finishColorIE = "'#" + (rtlEnabled ? "" : "00") + colorAsHex + "'";
                            return ["background-image: -webkit-linear-gradient(180deg, " + startColor + ", " + finishColor + ")", "background-image: -moz-linear-gradient(-90deg, " + startColor + ", " + finishColor + ")", "background-image: -ms-linear-gradient(-90deg, " + startColor + ", " + finishColor + ")", "background-image: -o-linear-gradient(-90deg, " + startColor + ", " + finishColor + ")", "background-image: linear-gradient(-90deg, " + startColor + ", " + finishColor + ")", "filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr=" + startColorIE + ", endColorstr=" + finishColorIE + ")", "-ms-filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr=" + startColorIE + ", endColorstr=" + finishColorIE + ")"].join(";")
                        };
                    $el.attr("style", combineGradientString.call(this, colorAsRgb, colorAsHex))
                }};
        DX.registerComponent("dxColorPicker", ui.dxDropDownEditor.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    _dragCoordinatesUpdater: null,
                    _standAlone: false,
                    value: "#000000",
                    editAlphaChannel: false,
                    applyButtonText: Globalize.localize("OK"),
                    cancelButtonText: Globalize.localize("Cancel")
                })
            },
            _setCurrentColor: function(value) {
                var newColor = new DX.Color(value);
                if (!newColor.colorIsInvalid) {
                    this._currentColor = new DX.Color(value);
                    this._alpha = this._currentColor.a
                }
                else
                    this.option("value", this._currentColor.baseColor)
            },
            _initColorAndOpacity: function() {
                this._setCurrentColor(this.option("value"))
            },
            _init: function() {
                this.callBase();
                this._initColorAndOpacity()
            },
            _render: function() {
                this.callBase();
                this._element().addClass(COLOR_PICKER_CLASS);
                if (this.option("_standAlone")) {
                    this._element().addClass("dx-standalone-colorpicker");
                    this._element().find(".dx-dropdowneditor-button").trigger("dxclick")
                }
            },
            _optionChanged: function(name, value) {
                switch (name) {
                    case"value":
                        this._input().val(value);
                        this._setCurrentColor(value);
                        this._makeTransparentBackground(this._$colorResultPreview);
                        this.callBase.apply(this, arguments);
                        break;
                    case"applyButtonText":
                        this._$applyButton.dxButton("instance").option("text", value);
                        break;
                    case"cancelButtonText":
                        this._$cancelButton.dxButton("instance").option("text", value);
                        break;
                    case"editAlphaChannel":
                        if (this._$colorPickerContainer) {
                            this._renderHtmlRows();
                            this._toggleContainerClass();
                            this._renderAlphaChannelElements()
                        }
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _handleValueChangeEvent: function(e) {
                if (this._dropDownVisible()) {
                    this._setCurrentColor(this._input().val());
                    this._refreshDropDown()
                }
                this.callBase(e)
            },
            _makeRgba: function() {
                return "rgba(" + [this._currentColor.r, this._currentColor.g, this._currentColor.b, this._alpha].join(", ") + ")"
            },
            _makeTransparentBackground: function($el) {
                if (DX.browser.msie && DX.browser.version === "8.0")
                    $el.css({
                        background: this._currentColor.toHex(),
                        filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + this._alpha * 100 + ")"
                    });
                else
                    $el.css("backgroundColor", this._makeRgba())
            },
            _renderInput: function() {
                this._$colorPickerInputContainer = $("<div/>").addClass(COLOR_PICKER_INPUT_CONTAINER_CLASS);
                this._$colorResultPreview = htmlCreator.createElement("div", COLOR_PICKER_COLOR_RESULT_PREVIEW, this._$colorPickerInputContainer);
                this._makeTransparentBackground(this._$colorResultPreview);
                this.callBase(this._$colorPickerInputContainer);
                this._input().addClass(COLOR_PICKER_INPUT_CLASS)
            },
            _renderValue: function(formattedValue) {
                this.callBase(this.option("editAlphaChannel") ? this._makeRgba() : this.option("value"))
            },
            _closeOutsideDropDownHandler: function(e, ignoreContainerClicks) {
                this.callBase(e, true)
            },
            _hideOnBlur: function() {
                return false
            },
            _createDropDown: function() {
                var that = this;
                this.callBase({
                    height: "",
                    width: "",
                    contentReadyAction: function() {
                        that._createColorPickerContainer()
                    }
                })
            },
            _showDropDown: function() {
                if (!this._dropDownVisible()) {
                    this.callBase();
                    this._refreshDropDown()
                }
            },
            _hideDropDown: function() {
                if (this._dropDownVisible()) {
                    this._initColorAndOpacity();
                    this.callBase()
                }
            },
            _calculateRowsCount: function() {
                var rowCount = this.option("editAlphaChannel") ? 3 : 2,
                    $renderedRows = this._$colorPickerContainer.find("." + COLOR_PICKER_ROW_CLASS);
                if (this.option("editAlphaChannel") && $renderedRows.length === 2)
                    rowCount = 1;
                if (!this.option("editAlphaChannel") && $renderedRows.length === 3)
                    rowCount = 0;
                return rowCount
            },
            _renderHtmlRows: function() {
                var $renderedRows = this._$colorPickerContainer.find("." + COLOR_PICKER_ROW_CLASS),
                    rowCount = this._calculateRowsCount($renderedRows);
                if (rowCount) {
                    var $rows = htmlCreator.createHtmlRows(rowCount);
                    if (rowCount === 1)
                        this._$colorPickerContainer.find("." + COLOR_PICKER_ROW_CLASS).eq(0).after($rows);
                    else
                        this._$colorPickerContainer.append($rows)
                }
                else
                    $renderedRows.eq(1).remove()
            },
            _toggleContainerClass: function() {
                this._$colorPickerContainer.toggleClass(COLOR_PICKER_OVERLAY_WITHOUT_ALPHA_CHANNEL_CLASS, !this.option("editAlphaChannel"))
            },
            _renderAlphaChannelElements: function() {
                if (this.option("editAlphaChannel")) {
                    this._renderAlphaChannelScale();
                    this._renderAlphaChannelInput()
                }
            },
            _createColorPickerContainer: function() {
                var $parent = this._dropDown.content();
                if (this.option("_standAlone")) {
                    this._dropDown.hide();
                    $parent = this._element()
                }
                else
                    this._dropDown.content().addClass(COLOR_PICKER_OVERLAY_CLASS);
                this._$colorPickerContainer = htmlCreator.createElement("div", COLOR_PICKER_CONTAINER_CLASS, $parent);
                this._renderHtmlRows();
                this._toggleContainerClass();
                this._createPalette();
                this._renderHueScale();
                this._renderControlsContainer();
                this._renderControls();
                this._renderAlphaChannelElements();
                this._renderButtons()
            },
            _createPalette: function() {
                var $paletteCell = htmlCreator.createHtmlCellInsideRow("first", this._$colorPickerContainer, "dx-palette-cell"),
                    $paletteGradientWhite = htmlCreator.createElement("div", [COLOR_PICKER_PALETTE_GRADIENT_CLASS, COLOR_PICKER_PALETTE_GRADIENT_WHITE_CLASS]),
                    $paletteGradientBlack = htmlCreator.createElement("div", [COLOR_PICKER_PALETTE_GRADIENT_CLASS, COLOR_PICKER_PALETTE_GRADIENT_BLACK_CLASS]);
                this._$palette = htmlCreator.createElement("div", COLOR_PICKER_PALETTE_CLASS, $paletteCell).css("backgroundColor", this._currentColor.getPureColor().toHex());
                this._createColorChooser();
                this._$palette.append([$paletteGradientWhite, $paletteGradientBlack])
            },
            _updateColor: function(isHex) {
                var rgba,
                    newColor;
                if (isHex)
                    newColor = this._validateHex("#" + this._$hexInput.val());
                else {
                    rgba = this._validateRgb();
                    if (this._$alphaChannelInput) {
                        rgba.push(this._$alphaChannelInput.val());
                        newColor = "rgba(" + rgba.join(", ") + ")"
                    }
                    else
                        newColor = "rgb(" + rgba.join(", ") + ")"
                }
                this._currentColor = new DX.Color(newColor);
                this._refreshDropDown()
            },
            _refreshDropDown: function() {
                this._placeHueMarker();
                this._placeColorChooser();
                this._updateColorParamsAndColorPreview();
                this._$palette.css("backgroundColor", this._currentColor.getPureColor().toHex());
                if (this._$alphaChannelHandle) {
                    this._updateColorTransparence(this._currentColor.a);
                    this._placeAlphaChannelHandle()
                }
            },
            _validateHex: function(hex) {
                return this._currentColor.isValidHex(hex) ? hex : this._currentColor.toHex()
            },
            _validateRgb: function() {
                var r = Number(this._$rgbInputs[0].val()),
                    g = Number(this._$rgbInputs[1].val()),
                    b = Number(this._$rgbInputs[2].val());
                if (!this._currentColor.isValidRGB(r, g, b)) {
                    r = this._currentColor.r;
                    g = this._currentColor.g;
                    b = this._currentColor.b
                }
                return [r, g, b]
            },
            _placeHueMarker: function() {
                var hueScaleHeight = this._$hueScale.parent().outerHeight(),
                    handleHeight = this._$hueScaleHandle.height();
                var top = hueScaleHeight - hueScaleHeight * this._currentColor.hsv.h / 360 - handleHeight / 2;
                if (hueScaleHeight < top + handleHeight)
                    top = hueScaleHeight - handleHeight;
                if (top < 0)
                    top = 0;
                this._$hueScaleHandle.css("top", Math.round(top))
            },
            _updateColorSaturation: function(value) {
                var hue = this._currentColor.hsv.h,
                    saturation = Math.round(value * 100 / this._$palette.width()),
                    value = this._currentColor.hsv.v;
                this._updateColorFromHsv(hue, saturation, value)
            },
            _updateColorValue: function(value) {
                var hue = this._currentColor.hsv.h,
                    saturation = this._currentColor.hsv.s,
                    value = 100 - Math.round(value * 100 / this._$palette.height());
                this._updateColorFromHsv(hue, saturation, value)
            },
            _updateColorHue: function(value) {
                var hue = 360 - Math.round((value + this._$hueScaleHandle.outerHeight() / 2) * 360 / this._$hueScale.height()),
                    saturation = this._currentColor.hsv.s,
                    value = this._currentColor.hsv.v;
                hue = hue < 0 ? 0 : hue;
                this._updateColorFromHsv(hue, saturation, value);
                this._$palette.css("backgroundColor", this._currentColor.getPureColor().toHex())
            },
            _updateColorTransparence: function(transparence) {
                this._$alphaChannelInput.val(transparence);
                this._alpha = transparence;
                this._makeTransparentBackground(this._$newColor)
            },
            _calculateColorTransparenceByScaleWidth: function(value) {
                var handleHalfWidth = this._$alphaChannelHandle.width() / 2,
                    alphaScaleWidth = this._$alphaChannelScale.width(),
                    rtlEnabled = this.option("rtlEnabled"),
                    transparence = value / this._$alphaChannelScale.width();
                transparence = rtlEnabled ? transparence : 1 - transparence;
                if (handleHalfWidth === value)
                    transparence = rtlEnabled ? 0 : 1;
                else if (value >= alphaScaleWidth - handleHalfWidth)
                    transparence = rtlEnabled ? 1 : 0;
                else if (transparence < 1)
                    transparence = transparence.toFixed(2);
                this._updateColorTransparence(transparence)
            },
            _updateColorFromHsv: function(hue, saturation, value) {
                this._currentColor = new DX.Color("hsv(" + [hue, saturation, value].join(",") + ")");
                this._updateColorParamsAndColorPreview()
            },
            _updateColorParamsAndColorPreview: function() {
                this._$hexInput.val(this._currentColor.toHex().replace("#", ""));
                this._$rgbInputs[0].val(this._currentColor.r);
                this._$rgbInputs[1].val(this._currentColor.g);
                this._$rgbInputs[2].val(this._currentColor.b);
                this._makeTransparentBackground(this._$newColor);
                if (this.option("editAlphaChannel"))
                    colorHelper.makeCSSLinearGradient.call(this, this._$alphaChannelScale)
            },
            _createColorChooser: function() {
                this._$colorChooser = htmlCreator.createElement("div", COLOR_PICKER_COLOR_CHOOSER_CLASS, this._$palette).colorPickerDrag({
                    verticalMotionCallback: $.proxy(this._updateColorValue, this),
                    horizontalMotionCallback: $.proxy(this._updateColorSaturation, this),
                    enableStripHalfOfWidth: true,
                    enableStripHalfOfHeight: true,
                    _coordinatesUpdater: this.option("_dragCoordinatesUpdater")
                });
                this._placeColorChooser()
            },
            _placeColorChooser: function() {
                var paletteHeight = this._$palette.height(),
                    colorChooserPosition = {
                        x: Math.round(this._$palette.width() * this._currentColor.hsv.s / 100 - this._$colorChooser.width() / 2),
                        y: Math.round(paletteHeight - paletteHeight * this._currentColor.hsv.v / 100 - this._$colorChooser.height() / 2)
                    };
                this._$colorChooser.css({
                    left: colorChooserPosition.x,
                    top: colorChooserPosition.y
                })
            },
            _renderHueScale: function() {
                var $hueScaleCell = htmlCreator.createHtmlCellInsideRow("first", this._$colorPickerContainer, "dx-hue-scale-cell");
                this._$hueScale = htmlCreator.createElement("div", COLOR_PICKER_HUE_SCALE_CLASS, $hueScaleCell);
                this._$hueScale.wrap("<div class=\"" + COLOR_PICKER_HUE_SCALE_WRAPPER_CLASS + "\"/>");
                this._renderHueScaleHandle()
            },
            _renderHueScaleHandle: function() {
                this._$hueScaleHandle = htmlCreator.createElement("div", COLOR_PICKER_HUE_SCALE_HANDLE_CLASS, this._$hueScale.closest("." + COLOR_PICKER_HUE_SCALE_WRAPPER_CLASS)).colorPickerDrag({
                    enableHorizontalMotion: false,
                    verticalMotionCallback: $.proxy(this._updateColorHue, this),
                    _coordinatesUpdater: this.option("_dragCoordinatesUpdater")
                });
                this._placeHueMarker()
            },
            _renderControlsContainer: function() {
                var $controlsContainerCell = htmlCreator.createHtmlCellInsideRow("first", this._$colorPickerContainer);
                this._$controlsContainer = htmlCreator.createElement("div", COLOR_PICKER_CONTROLS_CONTAINER_CLASS, $controlsContainerCell)
            },
            _renderControls: function() {
                this._renderColorsPreview();
                this._renderRgbInputs();
                this._renderHexInput()
            },
            _renderButtons: function() {
                var $buttonContainerCell = htmlCreator.createHtmlCellInsideRow("last", this._$colorPickerContainer, "dx-buttons-cell");
                this._$buttonContainer = htmlCreator.createElement("div", COLOR_PICKER_BUTTONS_CONTAINER_CLASS, $buttonContainerCell);
                this._renderApplyButton();
                this._renderCancelButton()
            },
            _renderApplyButton: function() {
                this._$applyButton = htmlCreator.createElement("div", COLOR_PICKER_APPLY_BUTTON_CLASS, this._$buttonContainer).dxButton({
                    text: this.option("applyButtonText"),
                    clickAction: $.proxy(this._applyColor, this)
                })
            },
            _applyColor: function() {
                var colorValue = this.option("editAlphaChannel") ? this._makeRgba() : this._currentColor.toHex();
                this._input().val(colorValue);
                this._makeTransparentBackground(this._$colorResultPreview);
                this._makeTransparentBackground(this._$currentColor);
                this.option("value", colorValue);
                this._hideDropDown()
            },
            _cancelChanges: function() {
                if (!this.option("_standAlone"))
                    this._hideDropDown();
                else {
                    this._initColorAndOpacity();
                    this._refreshDropDown()
                }
            },
            _renderCancelButton: function() {
                this._$cancelButton = htmlCreator.createElement("div", COLOR_PICKER_CANCEL_BUTTON_CLASS, this._$buttonContainer).dxButton({
                    text: this.option("cancelButtonText"),
                    clickAction: $.proxy(this._cancelChanges, this)
                })
            },
            _renderRgbInputs: function() {
                this._$rgbInputsWithLabels = [htmlCreator.createInputWithLabel("R", COLOR_PICKER_RED_LABEL_CLASS, COLOR_PICKER_RED_INPUT_CLASS), htmlCreator.createInputWithLabel("G", COLOR_PICKER_GREEN_LABEL_CLASS, COLOR_PICKER_GREEN_INPUT_CLASS), htmlCreator.createInputWithLabel("B", COLOR_PICKER_BLUE_LABEL_CLASS, COLOR_PICKER_BLUE_INPUT_CLASS)];
                this._$rgbInputs = [this._$rgbInputsWithLabels[0].find("input").val(this._currentColor.r).on("change", $.proxy(this._updateColor, this, false)), this._$rgbInputsWithLabels[1].find("input").val(this._currentColor.g).on("change", $.proxy(this._updateColor, this, false)), this._$rgbInputsWithLabels[2].find("input").val(this._currentColor.b).on("change", $.proxy(this._updateColor, this, false))];
                this._$controlsContainer.append(this._$rgbInputsWithLabels)
            },
            _renderHexInput: function() {
                var $hexInputWithLabel = htmlCreator.createInputWithLabel("#", COLOR_PICKER_HEX_LABEL_CLASS, COLOR_PICKER_HEX_INPUT_CLASS).appendTo(this._$controlsContainer);
                this._$hexInput = $hexInputWithLabel.find("input").val(this._currentColor.toHex().replace("#", "")).on("change", $.proxy(this._updateColor, this, true))
            },
            _renderColorsPreview: function() {
                var $colorsPreviewContainer = htmlCreator.createElement("div", COLOR_PICKER_COLOR_PREVIEW_CONTAINER_CLASS, this._$controlsContainer),
                    $colorsPreviewContainerInner = htmlCreator.createElement("div", COLOR_PICKER_COLOR_PREVIEW_CONTAINER_INNER_CLASS, $colorsPreviewContainer);
                this._$currentColor = htmlCreator.createElement("div", [COLOR_PICKER_COLOR_PREVIEW, COLOR_PICKER_CURRENT_COLOR_PREVIEW]);
                this._$newColor = htmlCreator.createElement("div", [COLOR_PICKER_COLOR_PREVIEW, COLOR_PICKER_NEW_COLOR_PREVIEW]);
                this._makeTransparentBackground(this._$currentColor);
                this._makeTransparentBackground(this._$newColor);
                $colorsPreviewContainerInner.append([this._$currentColor, this._$newColor])
            },
            _renderAlphaChannelScale: function() {
                var $alphaChannelScaleCell = htmlCreator.createHtmlCellInsideRow(1, this._$colorPickerContainer, COLOR_PICKER_ALPHA_CHANNEL_CELL_CLASS),
                    $alphaChannelBorder = htmlCreator.createElement("div", COLOR_PICKER_ALPHA_CHANNEL_BORDER_CLASS, $alphaChannelScaleCell),
                    $alphaChannelScaleWrapper = htmlCreator.createElement("div", COLOR_PICKER_ALPHA_CHANNEL_SCALE_WRAPPER_CLASS, $alphaChannelBorder);
                this._$alphaChannelScale = htmlCreator.createElement("div", COLOR_PICKER_ALPHA_CHANNEL_SCALE_CLASS, $alphaChannelScaleWrapper);
                colorHelper.makeCSSLinearGradient.call(this, this._$alphaChannelScale);
                this._renderAlphaChannelHandle($alphaChannelScaleCell)
            },
            _renderAlphaChannelInput: function() {
                var that = this,
                    $alphaChannelInputCell = htmlCreator.createHtmlCellInsideRow(1, this._$colorPickerContainer),
                    $alphaChannelInputWithLabel = htmlCreator.createInputWithLabel("Alpha", COLOR_PICKER_ALPHA_CHANNEL_LABEL_CLASS, COLOR_PICKER_ALPHA_CHANNEL_INPUT_CLASS).appendTo($alphaChannelInputCell);
                this._$alphaChannelInput = $alphaChannelInputWithLabel.find("input").val(this._alpha).on("change", function() {
                    var value = Number($(this).val());
                    value = that._currentColor.isValidAlpha(value) ? value : that._alpha;
                    that._updateColorTransparence(value);
                    that._placeAlphaChannelHandle()
                })
            },
            _renderAlphaChannelHandle: function($parent) {
                this._$alphaChannelHandle = htmlCreator.createElement("div", COLOR_PICKER_ALPHA_CHANNEL_HANDLE_CLASS, $parent).colorPickerDrag({
                    enableVerticalMotion: false,
                    horizontalMotionCallback: $.proxy(this._calculateColorTransparenceByScaleWidth, this),
                    _coordinatesUpdater: this.option("_dragCoordinatesUpdater")
                });
                this._placeAlphaChannelHandle()
            },
            _placeAlphaChannelHandle: function() {
                var alphaChannelScaleWidth = this._$alphaChannelScale.closest("." + COLOR_PICKER_ALPHA_CHANNEL_CELL_CLASS).outerWidth(),
                    handleWidth = this._$alphaChannelHandle.width();
                var left = alphaChannelScaleWidth - alphaChannelScaleWidth * this._alpha - handleWidth / 2;
                if (left < 0)
                    left = 0;
                if (alphaChannelScaleWidth < left + handleWidth)
                    left = alphaChannelScaleWidth - handleWidth;
                this._$alphaChannelHandle.css(this.option("rtlEnabled") ? "right" : "left", left)
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.menuBase.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            DXMENU = 'dxMenu',
            CLICK = events.addNamespace('dxclick', DXMENU),
            MOUSEENTER = events.addNamespace('mouseenter', DXMENU),
            MOUSELEAVE = events.addNamespace('mouseleave', DXMENU),
            DXPOINTERDOWN = events.addNamespace('dxpointerdown', DXMENU),
            MOUSEMOVE = events.addNamespace('mousemove', DXMENU);
        var DX_MENU_CLASS = 'dx-menu',
            DX_MENU_ITEM_CLASS = DX_MENU_CLASS + '-item',
            DX_MENU_ITEM_HOVERED_CLASS = 'dx-state-hover',
            DX_MENU_ITEM_CAPTION_CLASS = DX_MENU_ITEM_CLASS + '-text',
            DX_MENU_ITEM_POPOUT_CLASS = DX_MENU_ITEM_CLASS + '-popout',
            DX_MENU_ITEM_POPOUT_CONTAINER_CLASS = DX_MENU_ITEM_POPOUT_CLASS + '-container',
            DX_MENU_ITEM_DISABLED_CLASS = DX_MENU_ITEM_CLASS + '-disabled',
            DX_MENU_ITEM_SELECTED_CLASS = DX_MENU_ITEM_CLASS + '-selected',
            DX_MENU_ITEM_WRAPPER_CLASS = DX_MENU_ITEM_CLASS + '-wrapper',
            DX_MENU_RTL_CLASS = DX_MENU_CLASS + '-rtl',
            DX_MENU_ICON_CLASS = 'dx-menu-icon',
            DX_ICON_CLASS = 'dx-icon';
        var dxMenuBase = ui.CollectionContainerWidget.inherit({
                _itemRenderDefault: function(item, index, $itemElement) {
                    var $itemContent,
                        rtlEnabled;
                    if (!utils.isDefined(item))
                        return;
                    if (item.visible !== undefined && !item.visible)
                        $itemElement.hide();
                    if (item.disabled)
                        $itemElement.addClass(DX_MENU_ITEM_DISABLED_CLASS);
                    rtlEnabled = !!this.option('rtlEnabled');
                    if (rtlEnabled)
                        $itemElement.addClass(DX_MENU_RTL_CLASS);
                    $itemContent = $('<div>').addClass('dx-menu-item-content').appendTo($itemElement);
                    this._renderImage(item, $itemContent);
                    this._renderCaption(item, $itemContent);
                    this._renderPopout(item, $itemContent)
                },
                _renderImage: function(item, $itemContent) {
                    var $itemImage,
                        $imageContainer;
                    if (item.icon)
                        $itemImage = $('<span>').addClass(DX_ICON_CLASS + "-" + item.icon).appendTo($itemContent);
                    else if (item.iconSrc)
                        $itemImage = $('<span>').attr('src', item.iconSrc).appendTo($itemContent);
                    if ($itemImage)
                        $itemImage.addClass(DX_MENU_ICON_CLASS)
                },
                _renderPopout: function(item, $itemContent) {
                    var $popOutImage,
                        $popOutContainer;
                    if (this._hasChildren(item)) {
                        $popOutContainer = $('<span>').addClass(DX_MENU_ITEM_POPOUT_CONTAINER_CLASS).appendTo($itemContent);
                        $popOutImage = $('<div>').addClass(DX_MENU_ITEM_POPOUT_CLASS).appendTo($popOutContainer)
                    }
                },
                _renderCaption: function(item, $itemContent) {
                    var $itemCaption;
                    $itemCaption = $('<span>').addClass(DX_MENU_ITEM_CAPTION_CLASS);
                    if ($.isPlainObject(item)) {
                        if (item.text)
                            $itemCaption.text(item.text)
                    }
                    else
                        $itemCaption.html(String(item));
                    $itemContent.append($itemCaption)
                },
                _renderItemHotTrack: function($item, showHotTrack) {
                    var $itemWrapper,
                        menuItem;
                    menuItem = $item.data(this._itemDataKey());
                    if (menuItem == this.option('selectedItem') && showHotTrack)
                        return;
                    if (!!this.option('hoverStateEnabled')) {
                        $itemWrapper = $item.parents('.' + DX_MENU_ITEM_WRAPPER_CLASS).eq(0);
                        if ($itemWrapper.length)
                            $itemWrapper.toggleClass(DX_MENU_ITEM_HOVERED_CLASS, showHotTrack)
                    }
                },
                _itemDataKey: function() {
                    return 'dxMenuItemDataKey'
                },
                _itemClass: function() {
                    return DX_MENU_ITEM_CLASS
                },
                _itemWrapperSelector: function() {
                    return '.' + DX_MENU_ITEM_WRAPPER_CLASS
                },
                _attachItemHoverEvents: function() {
                    var itemSelector = this._itemWrapperSelector(),
                        mouseEnterEventName,
                        mouseLeaveEventName,
                        itemMouseEnterAction = this._createAction($.proxy(function(e) {
                            this._handleItemMouseEnter(e.jQueryEvent)
                        }, this)),
                        itemMouseLeaveAction = this._createAction($.proxy(function(e) {
                            this._handleItemMouseLeave(e.jQueryEvent)
                        }, this));
                    mouseEnterEventName = events.addNamespace('mouseenter', this.NAME);
                    mouseLeaveEventName = events.addNamespace('mouseleave', this.NAME);
                    this._itemContainer().off(mouseEnterEventName, itemSelector).on(mouseEnterEventName, itemSelector, $.proxy(function(e) {
                        itemMouseEnterAction({jQueryEvent: e})
                    }, this));
                    this._itemContainer().off(mouseLeaveEventName, itemSelector).on(mouseLeaveEventName, itemSelector, $.proxy(function(e) {
                        itemMouseLeaveAction({jQueryEvent: e})
                    }, this))
                },
                _handleItemMouseMove: function(eventArgs) {
                    var that = this,
                        $item = that._getItemElementByEventArgs(eventArgs);
                    if (!that._itemX)
                        that._itemX = 0;
                    if (!that._itemY)
                        that._itemY = 0;
                    if (Math.abs(event.pageX - that._itemX) > 4 || Math.abs(event.pageY - that._itemY) > 4) {
                        that._itemX = event.pageX;
                        that._itemY = event.pageY;
                        that._handleItemMouseMoveCore($item)
                    }
                },
                _hasChildren: function(item) {
                    return item.items && item.items.length > 0
                },
                _addCustomCssClass: function($element) {
                    var cssClass = $.trim(this.option('cssClass'));
                    if (cssClass)
                        $element.addClass(cssClass)
                },
                _init: function() {
                    var items = this.option('items');
                    this.callBase();
                    this.selectedItem = this.option('selectedItem');
                    this.enableSelection = this.option('allowSelectItem');
                    if (utils.isDefined(this.selectedItem) && this.selectedItem != null)
                        return;
                    this.selectedItem = this._getLastSelectedItem(items);
                    if (this.selectedItem)
                        this._setOptionInternal('selectedItem', this.selectedItem)
                },
                _setOptionInternal: function(name, value) {
                    this._optionChangedInternalFlag = true;
                    this.option(name, value);
                    this._optionChangedInternalFlag = false
                },
                _getLastSelectedItem: function(items) {
                    var that = this,
                        selectedItem = null,
                        nestedSelectedItem;
                    $.each(items, function(_, item) {
                        if (item) {
                            if (item.selected && item.selectable)
                                selectedItem = item;
                            if (utils.isArray(item.items)) {
                                nestedSelectedItem = that._getLastSelectedItem(item.items);
                                if (nestedSelectedItem)
                                    selectedItem = nestedSelectedItem
                            }
                        }
                    });
                    return selectedItem
                },
                _updateSelectedItemOnClick: function($itemElement, itemData) {
                    var prevSelItem = this.$selectedItemWrapper ? this.$selectedItemWrapper.children('.dx-menu-item').eq(0).data(this._itemDataKey()) : null,
                        actionArgs = {
                            selectedItem: itemData,
                            previousSelectedItem: prevSelItem,
                            itemElement: $itemElement,
                            itemData: itemData
                        },
                        itemSelectAction = this._createActionByOption("itemSelectAction", actionArgs);
                    if (this.option('allowSelectOnClick') && itemData.selectable) {
                        if (this.$selectedItemWrapper) {
                            this.$selectedItemWrapper.removeClass(DX_MENU_ITEM_SELECTED_CLASS);
                            if (this.$selectedItemWrapper.children('.dx-menu-item').eq(0).data(this._itemDataKey()))
                                this.$selectedItemWrapper.children('.dx-menu-item').eq(0).data(this._itemDataKey()).selected = false
                        }
                        this._setOptionInternal('selectedItem', null);
                        this.$selectedItemWrapper = $itemElement.parents('.dx-menu-item-wrapper').eq(0);
                        this.$selectedItemWrapper.addClass(DX_MENU_ITEM_SELECTED_CLASS);
                        this._setOptionInternal('selectedItem', itemData);
                        itemData.selected = true;
                        itemSelectAction(actionArgs)
                    }
                },
                _handleItemClick: function(e) {
                    var itemClickActionHandler = this._createAction($.proxy(this._updateOverlayVisibilityOnClick, this));
                    this._handleItemJQueryEvent(e, "itemClickAction", {}, {afterExecute: $.proxy(itemClickActionHandler, this)})
                },
                _getItemElementByEventArgs: function(eventArgs) {
                    return $(eventArgs.currentTarget).children(this._itemSelector()).first()
                }
            });
        ui.dxMenuBase = dxMenuBase
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.contextMenu.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            fx = DX.fx,
            DXMENU = 'dxContextMenu';
        var DX_MENU_CLASS = 'dx-menu',
            DX_MENU_ITEM_CLASS = DX_MENU_CLASS + '-item',
            DX_MENU_ITEM_SELECTED_CLASS = DX_MENU_ITEM_CLASS + '-selected',
            DX_MENU_PHONE_CLASS = 'dx-menu-phone-overlay',
            DX_MENU_ITEMS_CONTAINER_CLASS = DX_MENU_CLASS + '-items-container',
            DX_MENU_ITEM_WRAPPER_CLASS = DX_MENU_ITEM_CLASS + '-wrapper',
            DX_SUBMENU_CLASS = 'dx-submenu',
            DX_SUBMENU_LEVEL_ID = 'dxSubMenuLevel',
            DX_CONTEXT_MENU_CLASS = 'dx-context-menu',
            DX_WIDGET_CLASS = 'dx-widget',
            DX_MENU_SEPARATOR_CLASS = DX_MENU_CLASS + '-separator',
            DX_CONTEXT_MENU_CONTENT_DELIMITER_CLASS = DX_CONTEXT_MENU_CLASS + '-content-delimiter';
        DX.registerComponent("dxContextMenu", ui.dxMenuBase.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    items: [],
                    showSubmenuMode: 'onHover',
                    cssClass: '',
                    invokeOnlyFromCode: false,
                    position: {
                        at: 'center',
                        my: 'center'
                    },
                    hoverStateEnabled: true,
                    allowSelectItem: true,
                    allowSelectOnClick: true,
                    selectedItem: null,
                    itemSelectAction: null,
                    animation: {
                        show: {
                            type: "fade",
                            from: 0,
                            to: 1,
                            duration: 100
                        },
                        hide: {
                            type: 'fade',
                            from: 1,
                            to: 0,
                            duration: 100
                        }
                    },
                    showingAction: null,
                    shownAction: null,
                    hidingAction: null,
                    hiddenAction: null,
                    positioningAction: null,
                    direction: 'auto',
                    visible: false,
                    target: window
                })
            },
            _optionsByReference: function() {
                return $.extend(this.callBase(), {
                        animation: true,
                        position: true,
                        selectedItem: true
                    })
            },
            _itemContainer: function() {
                return this._overlay.content()
            },
            _clean: function() {
                if (this._overlay) {
                    this._overlay._element().remove();
                    this._overlay = null
                }
                this._target.off(events.addNamespace('dxhold', this.NAME));
                this._target.off(events.addNamespace('contextmenu', this.NAME))
            },
            _optionChanged: function(name, value) {
                if (this._optionChangedInternalFlag)
                    return;
                switch (name) {
                    case'visible':
                        this._toggleVisibility(value);
                        break;
                    case'disable':
                        break;
                    case'invokeOnlyFromCode':
                        break;
                    case'items':
                        if (this._overlay.option('visible'))
                            this._overlay.toggle(false);
                        this.selectedItem = this._getLastSelectedItem(value);
                        this._setOptionInternal('selectedItem', this.selectedItem);
                        this.callBase.apply(this, arguments);
                        break;
                    case'selectedItem':
                        this.selectedItem = value;
                        break;
                    default:
                        if (this._overlay.option('visible'))
                            this._overlay.toggle(false);
                        this.callBase.apply(this, arguments)
                }
            },
            _toggleVisibility: function(value) {
                value ? this.show() : this.hide()
            },
            _render: function() {
                this._target = $(this.option('target'));
                this.option('position');
                this.callBase()
            },
            _renderContentImpl: function() {
                this._renderContextMenuOverlay();
                this._renderAdditionGraphicsElements();
                this._attachItemHoverEvents();
                this._attachShowContextMenuEvents();
                this._addCustomCssClass(this._element());
                this.callBase()
            },
            _renderDimensions: function(){},
            _renderContextMenuOverlay: function() {
                var $overlayElement,
                    $overlayContent,
                    overlayOptions = this._getOverlayOptions();
                $overlayElement = $('<div>').appendTo(this._$element);
                $overlayElement.dxOverlay(overlayOptions);
                this._overlay = $overlayElement.dxOverlay('instance');
                $overlayContent = this._overlay.content();
                $overlayContent.addClass(DX_CONTEXT_MENU_CLASS).addClass(DX_WIDGET_CLASS);
                this._addCustomCssClass($overlayContent);
                this._addPlatformDependentClass($overlayContent);
                if (this.option('visible'))
                    this.show()
            },
            _addPlatformDependentClass: function($element) {
                if (DX.devices.current().phone)
                    $element.addClass(DX_MENU_PHONE_CLASS)
            },
            _renderAdditionGraphicsElements: function() {
                if (this.option('showAdditionalElements')) {
                    this.$contentDelimiter = $('<div>').appendTo(this._itemContainer());
                    this.$contentDelimiter.addClass(DX_CONTEXT_MENU_CONTENT_DELIMITER_CLASS);
                    this.$contentDelimiter.css('position', 'absolute').css('display', 'none').css('z-index', '2000')
                }
            },
            _attachShowContextMenuEvents: function() {
                var that = this,
                    holdEventName = events.addNamespace('dxhold', this.NAME),
                    rightClickEventName = events.addNamespace('contextmenu', this.NAME),
                    holdAction = this._createAction($.proxy(function(e) {
                        if (!that.option('invokeOnlyFromCode'))
                            if (e.jQueryEvent.originalEvent && e.jQueryEvent.originalEvent.pointerType !== 'mouse')
                                that.show(e.jQueryEvent)
                    }, this)),
                    contextMenuAction = this._createAction($.proxy(function(e) {
                        if (!that.option('invokeOnlyFromCode'))
                            if (that.show(e.jQueryEvent)) {
                                e.jQueryEvent.preventDefault();
                                if (e.jQueryEvent.originalEvent)
                                    e.jQueryEvent.originalEvent.returnValue = false
                            }
                    }, this));
                this._target.off(holdEventName).on(holdEventName, $.proxy(function(e) {
                    holdAction({jQueryEvent: e})
                }, this));
                this._target.off(rightClickEventName).on(rightClickEventName, $.proxy(function(e) {
                    contextMenuAction({jQueryEvent: e})
                }, this))
            },
            _renderItems: function(items) {
                var FIRST_SUBMENU_LEVEL = 1;
                this._renderSubMenu(items, this._itemContainer(), FIRST_SUBMENU_LEVEL)
            },
            _renderSubMenu: function(items, $holder, subMenuLevel) {
                var that = this,
                    $subMenu,
                    $itemsContainer,
                    $itemWrapper,
                    $item;
                $subMenu = $('<div>').appendTo($holder);
                $subMenu.addClass(DX_SUBMENU_CLASS);
                $subMenu.data(DX_SUBMENU_LEVEL_ID, subMenuLevel);
                $subMenu.css('display', subMenuLevel === 1 ? 'block' : 'none');
                $itemsContainer = $('<ul>').appendTo($subMenu);
                $itemsContainer.addClass(DX_MENU_ITEMS_CONTAINER_CLASS);
                if (subMenuLevel === 1) {
                    if (that.option('width'))
                        $itemsContainer.css('min-width', that.option('width'));
                    if (that.option('height'))
                        $itemsContainer.css('min-height', that.option('height'))
                }
                $.each(items, function(index, item) {
                    if (item) {
                        that._renderSeparator(item, index, $itemsContainer);
                        $itemWrapper = $('<li>').appendTo($itemsContainer);
                        $itemWrapper.addClass(DX_MENU_ITEM_WRAPPER_CLASS);
                        $item = that._renderItem(index, item, $itemWrapper);
                        if (that.enableSelection && item === that.selectedItem) {
                            $itemWrapper.addClass(DX_MENU_ITEM_SELECTED_CLASS);
                            that.$selectedItemWrapper = $itemWrapper
                        }
                        if (that._hasChildren(item))
                            that._renderSubMenu(item.items, $item, ++subMenuLevel)
                    }
                })
            },
            _renderSeparator: function(item, index, $itemsContainer) {
                var $separator;
                if (item.beginGroup && index > 0) {
                    $separator = $('<li>').appendTo($itemsContainer);
                    $separator.addClass(DX_MENU_SEPARATOR_CLASS)
                }
            },
            _showAdditionalGraphicsElements: function() {
                var $subMenu = this._itemContainer().children('.dx-submenu').eq(0),
                    $rootItem = this.option('position').of,
                    positionAt = this.option('position').at,
                    positionMy = this.option('position').my,
                    position = {of: $subMenu};
                if (this.$contentDelimiter) {
                    this.$contentDelimiter.css('display', 'block');
                    if (positionAt === 'left bottom' && positionMy === 'left top' || positionAt === 'right bottom' && positionMy === 'right top') {
                        this.$contentDelimiter.width($rootItem.width() < $subMenu.width() ? $rootItem.width() - 2 : $subMenu.width() - 2);
                        if (this._itemContainer().offset().top > $rootItem.offset().top) {
                            this.$contentDelimiter.height(2);
                            if (Math.round(this._itemContainer().offset().left) < Math.round($rootItem.offset().left)) {
                                position.offset = '-1 -1';
                                position.at = 'right top';
                                position.my = 'right top'
                            }
                            else {
                                position.offset = '1 -1';
                                position.at = 'left top';
                                position.my = 'left top'
                            }
                        }
                        else {
                            this.$contentDelimiter.height(3);
                            if (Math.round(this._itemContainer().offset().left) < Math.round($rootItem.offset().left)) {
                                position.offset = '-1 2';
                                position.at = 'right bottom';
                                position.my = 'right bottom'
                            }
                            else {
                                position.offset = '1 2';
                                position.at = 'left bottom';
                                position.my = 'left bottom'
                            }
                        }
                    }
                    else {
                        this.$contentDelimiter.width(2);
                        this.$contentDelimiter.height($rootItem.height() < $subMenu.height() ? $rootItem.height() - 2 : $subMenu.height() - 2);
                        if (this._itemContainer().offset().top < $rootItem.offset().top) {
                            position.offset = positionAt === 'right top' ? '-1 -1' : '1 -1';
                            position.at = positionAt === 'right top' ? 'left bottom' : 'right bottom';
                            position.my = position.at
                        }
                        else {
                            position.offset = positionAt === 'right top' ? '-1 1' : '1 1';
                            position.at = positionMy;
                            position.my = positionMy
                        }
                    }
                    DX.position(this.$contentDelimiter, position)
                }
            },
            _getOverlayOptions: function() {
                var that = this,
                    overlayAnimation = this.option('animation'),
                    overlayOptions = {
                        animation: overlayAnimation,
                        closeOnOutsideClick: $.proxy(that._closeOnOutsideClickHandler, that),
                        closeOnTargetScroll: true,
                        deferRendering: false,
                        disabled: this.option('disabled'),
                        position: {
                            at: this.option('position').at,
                            my: this.option('position').my,
                            of: this._target
                        },
                        shading: false,
                        showTitle: false,
                        height: 'auto',
                        width: 'auto',
                        rtlEnabled: this.option('rtlEnabled'),
                        showingAction: $.proxy(that._overlayShowingActionHandler, that),
                        shownAction: $.proxy(that._overlayShownActionHandler, that),
                        hidingAction: $.proxy(that._overlayHidingActionHandler, that),
                        hiddenAction: $.proxy(that._overlayHiddenActionHandler, that),
                        positionedAction: $.proxy(that._overlayPositionedActionHandler, that)
                    };
                return overlayOptions
            },
            _closeOnOutsideClickHandler: function(e) {
                if (e.target !== document) {
                    if ($(e.target).hasClass('dx-menu-item-content'))
                        if (this._$element.siblings()[0] === e.target)
                            return false;
                    if ($(e.target.parentElement).hasClass('dx-menu-item-content'))
                        if (this._$element.siblings()[0] === e.target.parentElement)
                            return false;
                    if ($(e.target).siblings().hasClass('dx-menu-item-content'))
                        if (this._$element.siblings()[0] === $(e.target).siblings()[0])
                            return false
                }
                return true
            },
            _overlayShowingActionHandler: function(arg) {
                var action = this._createActionByOption('showingAction', {});
                action(arg)
            },
            _overlayShownActionHandler: function(arg) {
                var action = this._createActionByOption('shownAction', {});
                action(arg)
            },
            _overlayHidingActionHandler: function(arg) {
                var action = this._createActionByOption('hidingAction', {});
                action(arg);
                this._hideAllShownSubMenus()
            },
            _overlayHiddenActionHandler: function(arg) {
                var action = this._createActionByOption('hiddenAction', {});
                action(arg);
                this._setOptionInternal('visible', false)
            },
            _overlayPositionedActionHandler: function() {
                this._showAdditionalGraphicsElements()
            },
            _handleItemMouseEnter: function(eventArgs) {
                var that = this,
                    mouseMoveEventName = events.addNamespace('mousemove', that.NAME),
                    $itemElement = that._getItemElementByEventArgs(eventArgs),
                    $subMenuElement = $itemElement.children('.dx-submenu'),
                    showSubmenuMode = that.option('showSubmenuMode');
                if ($itemElement.data(this._itemDataKey()).disabled)
                    return;
                that._renderItemHotTrack($itemElement, true);
                if (this.option('showSubmenuMode') !== 'onclick')
                    if ($subMenuElement.length > 0) {
                        that._showSubMenuGroup($subMenuElement, $itemElement);
                        if (showSubmenuMode && showSubmenuMode.toLowerCase() === 'onhoverstay')
                            $itemElement.off(mouseMoveEventName).on(mouseMoveEventName, function(e) {
                                that._handleItemMouseMove(e)
                            })
                    }
            },
            _handleItemMouseLeave: function(eventArgs) {
                var that = this,
                    $itemElement = that._getItemElementByEventArgs(eventArgs),
                    $subMenuElement = $itemElement.children('.dx-submenu');
                if ($itemElement.data(this._itemDataKey()).disabled)
                    return;
                that._renderItemHotTrack($itemElement, false);
                if ($subMenuElement.length > 0)
                    that._hideSubMenuGroup($subMenuElement)
            },
            _handleItemMouseMoveCore: function($item) {
                var $subMenuElement = $item.children('.dx-submenu');
                this._showSubMenuGroup($subMenuElement, $item)
            },
            _hideSubMenuGroup: function($subMenu) {
                var that = this,
                    showTimerId = $subMenu.data('data-show-timer'),
                    hideTimerId = $subMenu.data('data-hide-timer');
                clearTimeout(showTimerId);
                clearTimeout(hideTimerId);
                if (this._isSubMenuVisible($subMenu)) {
                    hideTimerId = setTimeout(function() {
                        that._hideSubMenuCore($subMenu)
                    }, 300);
                    $subMenu.data('data-hide-timer', hideTimerId)
                }
            },
            _showSubMenuGroup: function($subMenu, $itemElement, forceRestartTimer) {
                var that = this,
                    showTimerId = $subMenu.data('data-show-timer'),
                    hideTimerId = $subMenu.data('data-hide-timer');
                clearTimeout(showTimerId);
                clearTimeout(hideTimerId);
                if (forceRestartTimer || !this._isSubMenuVisible($subMenu)) {
                    showTimerId = setTimeout(function() {
                        that._showSubMenuCore($subMenu, that._getSubMenuPosition($itemElement))
                    }, 300);
                    $subMenu.data('data-show-timer', showTimerId)
                }
            },
            _getSubMenuPosition: function($rootItem) {
                var isVerticalMenu,
                    direction,
                    rtlEnabled,
                    position,
                    $rootItemWrapper;
                rtlEnabled = !!this.option('rtlEnabled');
                direction = this.option('direction').toLowerCase();
                $rootItemWrapper = $rootItem.parent('.dx-menu-item-wrapper');
                position = {
                    collision: 'flip',
                    of: $rootItemWrapper,
                    offset: {
                        h: 0,
                        v: -1
                    }
                };
                switch (direction) {
                    case'left':
                        position.at = 'left top';
                        position.my = 'right top';
                        break;
                    case'right':
                        position.at = 'right top';
                        position.my = 'left top';
                        break;
                    default:
                        if (rtlEnabled) {
                            position.at = 'left top';
                            position.my = 'right top'
                        }
                        else {
                            position.at = 'right top';
                            position.my = 'left top'
                        }
                        break
                }
                return position
            },
            _isSubMenuVisible: function($subMenu) {
                return $subMenu.css('display') !== 'none'
            },
            _animate: function($container, options) {
                fx.animate($container, options)
            },
            _stopAnimate: function($container) {
                fx.stop($container, true)
            },
            _showSubMenuCore: function($subMenu, position) {
                var animation = this.option('animation') ? this.option('animation').show : {};
                if (this._overlay && this._overlay.option('visible')) {
                    if (!utils.isDefined(this._shownSubMenus))
                        this._shownSubMenus = [];
                    if ($.inArray($subMenu, this._shownSubMenus))
                        this._shownSubMenus.push($subMenu);
                    $subMenu.css('display', 'block');
                    DevExpress.position($subMenu, position);
                    this._stopAnimate($subMenu);
                    this._animate($subMenu, animation)
                }
            },
            _hideSubMenuCore: function($subMenu) {
                var index = $.inArray($subMenu, this._shownSubMenus),
                    animation = this.option('animation') ? this.option('animation').hide : {};
                if (index >= 0)
                    this._shownSubMenus.splice(index, 1);
                this._stopAnimate($subMenu);
                this._animate($subMenu, animation.hide);
                $subMenu.css('display', 'none')
            },
            _updateOverlayVisibilityOnClick: function(actionArgs) {
                var $itemElement,
                    $subMenuElement;
                if (actionArgs.args.length && actionArgs.args[0]) {
                    actionArgs.args[0].jQueryEvent.stopPropagation();
                    $itemElement = actionArgs.args[0].itemElement;
                    $subMenuElement = $itemElement.children('.dx-submenu');
                    if ($itemElement.context === $subMenuElement.context && $subMenuElement.is(":visible"))
                        return;
                    if (!$itemElement.data(this._itemDataKey()) || $itemElement.data(this._itemDataKey()).disabled)
                        return;
                    this._updateSelectedItemOnClick($itemElement, actionArgs.args[0].itemData);
                    if ($subMenuElement.length === 0) {
                        var $prevSubMenu = $($itemElement.parents('.dx-submenu')[0]);
                        this._hideChildrenSubMenus($prevSubMenu);
                        if (!actionArgs.canceled && this._overlay && this._overlay.option('visible'))
                            this.option('visible', false)
                    }
                    else {
                        if (this._shownSubMenus && this._shownSubMenus.length > 0)
                            if (this._shownSubMenus[0].is($subMenuElement) || this._shownSubMenus[0].has($subMenuElement).length === 1)
                                this._hideChildrenSubMenus($subMenuElement);
                            else
                                this._hideAllShownSubMenus();
                        this._showSubMenuGroup($subMenuElement, $itemElement)
                    }
                }
            },
            _hideChildrenSubMenus: function($curSubMenu) {
                var that = this,
                    shownSubMenus = $.extend([], that._shownSubMenus);
                $.each(shownSubMenus, function(_, $subMenu) {
                    if ($curSubMenu.is($subMenu) || $curSubMenu.has($subMenu).length)
                        that._hideSubMenuCore($subMenu)
                })
            },
            _hideAllShownSubMenus: function() {
                var that = this,
                    shownSubMenus = $.extend([], that._shownSubMenus);
                $.each(shownSubMenus, function(_, $subMenu) {
                    that._hideSubMenuCore($subMenu)
                })
            },
            show: function(jqueryEvent) {
                var position = this.option('position'),
                    actionArgs,
                    positioningAction;
                if (jqueryEvent && jqueryEvent.preventDefault)
                    position = {
                        at: 'top left',
                        my: 'top left',
                        of: jqueryEvent
                    };
                if (!position.of)
                    position.of = this._target;
                actionArgs = {
                    position: position,
                    jQueryEvent: jqueryEvent
                };
                positioningAction = this._createActionByOption('positioningAction', actionArgs);
                positioningAction(actionArgs);
                if (!actionArgs.canceled && this._overlay) {
                    if (position) {
                        this._overlay.option('position', null);
                        this._overlay.option('position', position)
                    }
                    this._overlay.toggle(true);
                    this._setOptionInternal('visible', true)
                }
                return this.option('visible')
            },
            hide: function() {
                if (this._overlay) {
                    this._overlay.toggle(false);
                    this._setOptionInternal('visible', false)
                }
            }
        }))
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.menu.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            fx = DX.fx,
            DIV = '<div />',
            UL = '<ul />',
            DXMENU = 'dxMenu',
            DURATION = 50,
            CLICK = events.addNamespace('dxclick', DXMENU),
            MOUSEENTER = events.addNamespace('mouseenter', DXMENU),
            MOUSELEAVE = events.addNamespace('mouseleave', DXMENU),
            DXPOINTERDOWN = events.addNamespace('dxpointerdown', DXMENU),
            MOUSEMOVE = events.addNamespace('mousemove', DXMENU);
        var DX_MENU_CLASS = 'dx-menu',
            DX_MENU_VERTICAL_CLASS = DX_MENU_CLASS + '-vertical',
            DX_MENU_HORIZONTAL_CLASS = DX_MENU_CLASS + '-horizontal',
            DX_MENU_ITEM_CLASS = DX_MENU_CLASS + '-item',
            DX_MENU_ITEM_SELECTED_CLASS = DX_MENU_ITEM_CLASS + '-selected',
            DX_MENU_ITEMS_CONTAINER_CLASS = DX_MENU_CLASS + '-items-container',
            DX_MENU_ITEM_WITH_SUBMENU_CLASS = DX_MENU_ITEM_CLASS + '-with-submenu',
            DX_MENU_ITEM_WRAPPER_CLASS = DX_MENU_ITEM_CLASS + '-wrapper',
            DX_CONTEXT_MENU_CLASS = 'dx-context-menu',
            DX_MENU_SEPARATOR_CLASS = DX_MENU_CLASS + '-separator',
            DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS = DX_CONTEXT_MENU_CLASS + '-container-border';
        DX.registerComponent("dxMenu", ui.dxMenuBase.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    orientation: 'horizontal',
                    firstSubMenuDirection: 'auto',
                    showPopupMode: 'onclick',
                    items: [],
                    hoverStateEnabled: true,
                    allowSelectItem: true,
                    allowSelectOnClick: true,
                    selectedItem: null,
                    cssClass: '',
                    animation: {
                        show: {
                            type: "fade",
                            from: 0,
                            to: 1,
                            duration: 100
                        },
                        hide: {
                            type: 'fade',
                            from: 1,
                            to: 0,
                            duration: 100
                        }
                    },
                    submenuShowingAction: null,
                    submenuShownAction: null,
                    submenuHidingAction: null,
                    submenuHiddenAction: null,
                    itemSelectAction: null
                })
            },
            _optionsByReference: function() {
                return $.extend(this.callBase(), {
                        animation: true,
                        selectedItem: true
                    })
            },
            _render: function() {
                this.callBase();
                this._element().addClass(DX_MENU_CLASS);
                this._addCustomCssClass(this._element());
                this._attachItemHoverEvents()
            },
            _renderItems: function(items) {
                var that = this,
                    isVerticalMenu,
                    $rootGroup,
                    $itemsContainer,
                    $itemWrapper,
                    $item,
                    $popupMenu,
                    $separator;
                isVerticalMenu = that.option('orientation') === 'vertical';
                $rootGroup = $('<div>').appendTo(that._element());
                $rootGroup.addClass(isVerticalMenu ? DX_MENU_VERTICAL_CLASS : DX_MENU_HORIZONTAL_CLASS);
                $itemsContainer = $('<ul>').appendTo($rootGroup);
                $itemsContainer.addClass(DX_MENU_ITEMS_CONTAINER_CLASS);
                $itemsContainer.css('min-height', this._getValueHeight($rootGroup));
                $.each(items, function(index, item) {
                    if (item) {
                        that._renderSeparator(item, index, $itemsContainer);
                        $itemWrapper = $('<li>').appendTo($itemsContainer);
                        $itemWrapper.addClass(DX_MENU_ITEM_WRAPPER_CLASS);
                        $item = that._renderItem(index, item, $itemWrapper);
                        that._renderSelectedItem(item, $itemWrapper);
                        that._renderChildrenItems(item, $item)
                    }
                })
            },
            _renderSeparator: function(item, index, $itemsContainer) {
                var $separator;
                if (item.beginGroup && index > 0) {
                    $separator = $('<li>').appendTo($itemsContainer);
                    $separator.addClass(DX_MENU_SEPARATOR_CLASS)
                }
            },
            _renderSelectedItem: function(item, $itemWrapper) {
                if (this.option('allowSelectItem'))
                    if (item === this.selectedItem) {
                        $itemWrapper.addClass(DX_MENU_ITEM_SELECTED_CLASS);
                        this.$selectedItemWrapper = $itemWrapper
                    }
            },
            _renderChildrenItems: function(item, $item) {
                if (this._hasChildren(item)) {
                    this._createPopupMenu(item.items, $item, this.selectedItem).appendTo($item);
                    this._renderBorderElement($item)
                }
            },
            _renderBorderElement: function($item) {
                var $border = $('<div>').appendTo($item);
                $border.addClass(DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS);
                $border.css('display', 'none')
            },
            _getValueHeight: function($root) {
                var $div = $("<div>").html("Jj").css({
                        width: "auto",
                        position: "fixed",
                        top: "-3000px",
                        left: "-3000px"
                    }).appendTo($root),
                    height = $div.height();
                $div.remove();
                return height
            },
            _handleItemMouseEnter: function(eventArg) {
                var that = this,
                    DX_MENU_HOVERSTAY_TIMEOUT = 300,
                    mouseMoveEventName,
                    $item,
                    popupMenu,
                    showPopupMode,
                    isHoverStayMode;
                $item = that._getItemElementByEventArgs(eventArg);
                if ($item.data(this._itemDataKey()).disabled)
                    return;
                that._renderItemHotTrack($item, true);
                popupMenu = that._getPopupMenuByRootElement($item);
                showPopupMode = that.option('showPopupMode').toLowerCase();
                if (showPopupMode !== 'onclick' && popupMenu) {
                    clearTimeout(that._hidePopupMenuTimer);
                    clearTimeout(that._showPopupMenuTimer);
                    isHoverStayMode = that.option('showPopupMode') !== 'onhover';
                    if (isHoverStayMode && that.visiblePopupMenu == popupMenu && !popupMenu._overlay.option('visible')) {
                        mouseMoveEventName = events.addNamespace('mousemove', that.NAME);
                        $item.off(mouseMoveEventName).on(mouseMoveEventName, $.proxy(that._handleItemMouseMove, that));
                        that._showPopupMenuTimer = setTimeout(function() {
                            that._showPopupMenu(popupMenu, $item)
                        }, DX_MENU_HOVERSTAY_TIMEOUT)
                    }
                    else
                        that._showPopupMenu(popupMenu, $item)
                }
            },
            _handleItemMouseLeave: function(eventArg) {
                var that = this,
                    DX_MENU_HOVER_TIMEOUT = 50,
                    DX_MENU_HOVERSTAY_TIMEOUT = 300,
                    $item,
                    popupMenu,
                    showPopupMode,
                    timeout;
                showPopupMode = that.option('showPopupMode').toLowerCase();
                timeout = that.option('showPopupMode') !== 'onhover' ? DX_MENU_HOVERSTAY_TIMEOUT : DX_MENU_HOVER_TIMEOUT;
                $item = that._getItemElementByEventArgs(eventArg);
                if ($item.data(this._itemDataKey()).disabled)
                    return;
                that._renderItemHotTrack($item, false);
                if (showPopupMode !== 'onclick') {
                    clearTimeout(that._showPopupMenuTimer);
                    clearTimeout(that._hidePopupMenuTimer);
                    that._hidePopupMenuTimer = setTimeout(function() {
                        popupMenu = that._getPopupMenuByRootElement($item);
                        that._hidePopupMenu(popupMenu);
                        if (that.visiblePopupMenu == popupMenu)
                            that.visiblePopupMenu = null
                    }, timeout)
                }
            },
            _handleItemMouseMoveCore: function($item) {
                var that = this,
                    DX_MENU_HOVERSTAY_TIMEOUT = 300,
                    popupMenu;
                if (that._showPopupMenuTimer) {
                    clearTimeout(that._hidePopupMenuTimer);
                    clearTimeout(that._showPopupMenuTimer);
                    popupMenu = that._getPopupMenuByRootElement($item),
                    that._showPopupMenuTimer = setTimeout(function() {
                        that._showPopupMenu(popupMenu, $item)
                    }, DX_MENU_HOVERSTAY_TIMEOUT)
                }
            },
            _updateOverlayVisibilityOnClick: function(actionArgs) {
                var that = this,
                    $item,
                    popupMenu;
                if (actionArgs.args.length && actionArgs.args[0]) {
                    actionArgs.args[0].jQueryEvent.stopPropagation();
                    $item = actionArgs.args[0].itemElement;
                    if ($item.data(this._itemDataKey()).disabled)
                        return;
                    popupMenu = that._getPopupMenuByRootElement($item);
                    this._updateSelectedItemOnClick($item, actionArgs.args[0].itemData);
                    if (popupMenu)
                        if (popupMenu._overlay.option('visible')) {
                            if (that.option('showPopupMode') === 'onclick')
                                that._hidePopupMenu(popupMenu)
                        }
                        else
                            that._showPopupMenu(popupMenu, $item)
                }
            },
            _createPopupMenu: function(items, $rootItem, nestedSelectedItem) {
                var that = this,
                    popupMenu,
                    $popupMenuContainer = $('<div>'),
                    $popupMenuTarget = $('<div>'),
                    $popupMenuOverlayContent,
                    popupMenuMouseEnterName,
                    popupMenuMouseLeaveName;
                popupMenuMouseEnterName = events.addNamespace('mouseenter', that.NAME + '_popupMenu');
                popupMenuMouseLeaveName = events.addNamespace('mouseleave', that.NAME + '_popupMenu');
                $popupMenuContainer.dxContextMenu({
                    target: $popupMenuTarget,
                    items: items,
                    position: that._getPopupMenuPosition($rootItem),
                    showAdditionalElements: true,
                    selectedItem: nestedSelectedItem,
                    cssClass: this.option('cssClass'),
                    animation: this.option('animation'),
                    rtlEnabled: this.option('rtlEnabled'),
                    disabled: this.option('disabled'),
                    itemSelectAction: $.proxy(this._nestedItemSelectActionHandler, this),
                    itemClickAction: $.proxy(this._nestedItemClickActionHandler, this),
                    showingAction: $.proxy(this._contextMenuShowingActionHandler, this, $rootItem, popupMenu),
                    shownAction: $.proxy(this._contextMenuShownActionHandler, this, $rootItem, popupMenu),
                    hidingAction: $.proxy(this._contextMenuHidingActionHandler, this, $rootItem, popupMenu),
                    hiddenAction: $.proxy(this._contextMenuHiddenActionHandler, this, $rootItem, popupMenu)
                });
                $popupMenuContainer.addClass(DX_CONTEXT_MENU_CLASS);
                popupMenu = $popupMenuContainer.dxContextMenu('instance');
                $popupMenuOverlayContent = popupMenu._overlay.content();
                $popupMenuOverlayContent.off(popupMenuMouseEnterName).on(popupMenuMouseEnterName, null, $.proxy(this._handlePopupMenuMouseEnter, this, $rootItem));
                $popupMenuOverlayContent.off(popupMenuMouseLeaveName).on(popupMenuMouseLeaveName, null, $.proxy(this._handlePopupMenuMouseLeave, this, $rootItem));
                return $popupMenuContainer
            },
            _getPopupMenuPosition: function($rootItem) {
                var isVerticalMenu,
                    firstSubMenuDirection,
                    rtlEnabled,
                    popupMenuPosition;
                rtlEnabled = !!this.option('rtlEnabled');
                isVerticalMenu = this.option('orientation').toLowerCase() == 'vertical';
                firstSubMenuDirection = this.option('firstSubMenuDirection').toLowerCase();
                popupMenuPosition = {
                    collision: 'flip',
                    of: $rootItem
                };
                switch (firstSubMenuDirection) {
                    case'leftOrTop':
                        popupMenuPosition.at = isVerticalMenu ? 'left top' : 'left top';
                        popupMenuPosition.my = isVerticalMenu ? 'right top' : 'left bottom';
                        break;
                    case'rightOrBottom':
                        popupMenuPosition.at = isVerticalMenu ? 'right top' : 'left bottom';
                        popupMenuPosition.my = isVerticalMenu ? 'left top' : 'left top';
                        break;
                    case'auto':
                    default:
                        if (isVerticalMenu) {
                            popupMenuPosition.at = rtlEnabled ? 'left top' : 'right top';
                            popupMenuPosition.my = rtlEnabled ? 'right top' : 'left top'
                        }
                        else {
                            popupMenuPosition.at = rtlEnabled ? 'right bottom' : 'left bottom';
                            popupMenuPosition.my = rtlEnabled ? 'right top' : 'left top'
                        }
                        break
                }
                return popupMenuPosition
            },
            _nestedItemSelectActionHandler: function(arg) {
                this._updateSelectedItemOnClick(arg.itemElement, arg.itemData)
            },
            _nestedItemClickActionHandler: function(arg) {
                var action = this._createActionByOption('itemClickAction', {});
                action(arg)
            },
            _contextMenuShowingActionHandler: function($rootItem, popupMenu) {
                var action,
                    $borderElt,
                    animation;
                action = this._createActionByOption('submenuShowingAction', {});
                action({
                    rootItem: $rootItem,
                    popupMenu: popupMenu
                });
                $borderElt = $rootItem.children('.' + DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS);
                if (this._options.width !== undefined)
                    if (this._options.rtlEnabled)
                        $borderElt.width(this._$element.width() - $rootItem.position().right);
                    else
                        $borderElt.width(this._$element.width() - $rootItem.position().left);
                $borderElt.css('display', 'block');
                DX.fx.stop($borderElt, true);
                animation = this.option('animation') ? this.option('animation').show : {};
                DX.fx.animate($borderElt, animation);
                $rootItem.addClass(DX_MENU_ITEM_WITH_SUBMENU_CLASS)
            },
            _contextMenuShownActionHandler: function($rootItem, popupMenu) {
                var action = this._createActionByOption('submenuShownAction', {});
                action({
                    rootItem: $rootItem,
                    popupMenu: popupMenu
                })
            },
            _contextMenuHidingActionHandler: function($rootItem, popupMenu) {
                var action,
                    $borderElt,
                    animation;
                action = this._createActionByOption('submenuHidingAction', {});
                action({
                    rootItem: $rootItem,
                    popupMenu: popupMenu
                });
                $borderElt = $rootItem.children('.' + DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS);
                animation = this.option('animation') ? this.option('animation').hide : {};
                DX.fx.animate($borderElt, animation);
                $borderElt.css('display', 'none');
                $rootItem.removeClass(DX_MENU_ITEM_WITH_SUBMENU_CLASS)
            },
            _contextMenuHiddenActionHandler: function($rootItem, popupMenu) {
                var action = this._createActionByOption('submenuHiddenAction', {});
                action({
                    rootItem: $rootItem,
                    popupMenu: popupMenu
                })
            },
            _handlePopupMenuMouseEnter: function($rootItem) {
                this._hoveredPopupMenuContainer = $rootItem
            },
            _handlePopupMenuMouseLeave: function($rootItem) {
                var that = this,
                    popupMenu,
                    HOVER_TIMEOUT = 50;
                setTimeout(function() {
                    if (!that._hoveredPopupMenuContainer || !that._hoveredPopupMenuContainer.is(that._hoveredRootItem)) {
                        popupMenu = that._getPopupMenuByRootElement($rootItem);
                        if (popupMenu)
                            popupMenu.hide()
                    }
                    that._hoveredPopupMenuContainer = null
                }, HOVER_TIMEOUT)
            },
            _showPopupMenu: function(popupMenu, $popupMenuContainer) {
                if (utils.isDefined(this.visiblePopupMenu) && this.visiblePopupMenu !== popupMenu)
                    this.visiblePopupMenu.hide();
                this._renderItemHotTrack($popupMenuContainer, false);
                popupMenu.show();
                this.visiblePopupMenu = popupMenu;
                this._hoveredRootItem = $popupMenuContainer
            },
            _hidePopupMenu: function(popupMenu) {
                if (!this._hoveredRootItem || !this._hoveredRootItem.is(this._hoveredPopupMenuContainer))
                    if (popupMenu)
                        popupMenu.hide();
                this._hoveredRootItem = null
            },
            _optionChanged: function(name, value) {
                if (this._optionChangedInternalFlag)
                    return;
                if (this.visiblePopupMenu)
                    this.visiblePopupMenu.hide();
                switch (name) {
                    case'items':
                        this.selectedItem = this._getLastSelectedItem(value);
                        this._setOptionInternal('selectedItem', this.selectedItem);
                        this.callBase.apply(this, arguments);
                        break;
                    case'selectedItem':
                        this.selectedItem = value;
                        break;
                    default:
                        this.callBase.apply(this, arguments)
                }
            },
            _getPopupMenuByRootElement: function($rootItem) {
                var popupMenu = null,
                    $popupMenu;
                if ($rootItem) {
                    $popupMenu = $rootItem.children('.dx-context-menu');
                    if ($popupMenu.length > 0)
                        popupMenu = $popupMenu.dxContextMenu('instance')
                }
                return popupMenu
            },
            _containNode: function(hierarchy, node) {
                var that = this,
                    nestedResult = false,
                    result = false;
                $.each(hierarchy, function(_, curNode) {
                    if (curNode == node)
                        result = true;
                    if (curNode.items) {
                        nestedResult = that._containNode(curNode.items, node);
                        nestedResult ? result = nestedResult : result
                    }
                });
                return result
            }
        }));
        ui.dxMenu.__internals = {MENU_AMIMATION_DURATION: DURATION}
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.js */
    (function($, DX) {
        var ui = DX.ui,
            utils = DX.utils;
        var ModuleItem = DX.Class.inherit({
                ctor: function(component) {
                    var that = this;
                    that.component = component;
                    that.disposing = component.disposing;
                    that._actions = {};
                    $.each(this.callbackNames() || [], function(index, name) {
                        var flags = that.callbackFlags(name);
                        that[this] = $.Callbacks(flags)
                    })
                },
                callbackNames: function(){},
                callbackFlags: function(name){},
                publicMethods: function(){},
                init: function(){},
                option: function() {
                    return this.component.option.apply(this.component, arguments)
                },
                optionChanged: function(name, value, prevValue){},
                getController: function(name) {
                    return this.component._controllers[name]
                },
                getView: function(name) {
                    return this.component._views[name]
                },
                createAction: function(actionName, config) {
                    var action;
                    if (utils.isFunction(actionName)) {
                        action = this.component._createAction($.proxy(actionName, this), config);
                        return function(e) {
                                action({jQueryEvent: e})
                            }
                    }
                    else
                        this._actions[actionName] = this.option(actionName) ? this.component._createActionByOption(actionName, config) : null
                },
                executeAction: function(actionName, options) {
                    var action = this._actions[actionName];
                    return action && action(options)
                },
                dispose: function() {
                    var that = this;
                    $.each(that.callbackNames() || [], function() {
                        that[this].empty()
                    })
                }
            });
        var Controller = ModuleItem;
        var ViewController = Controller;
        var View = ViewController.inherit({
                _element: function() {
                    return this._$element
                },
                _renderCore: function(options){},
                _afterRender: function($root){},
                _parentElement: function() {
                    return this._$parent
                },
                ctor: function(component) {
                    this.callBase(component);
                    this.renderCompleted = $.Callbacks();
                    this.resizeCompleted = $.Callbacks()
                },
                isVisible: function() {
                    return true
                },
                getTemplate: function(name) {
                    return this.component._getTemplate(name)
                },
                render: function($parent, options) {
                    var $element = this._$element,
                        isVisible = this.isVisible();
                    this._$parent = $parent;
                    if (!$element)
                        $element = this._$element = $('<div />').appendTo($parent);
                    $element.toggle(isVisible);
                    if (isVisible) {
                        this._renderCore(options);
                        this._afterRender($parent);
                        this.renderCompleted.fire()
                    }
                },
                resize: function() {
                    this.isResizing = true;
                    this.resizeCompleted.fire();
                    this.isResizing = false
                },
                focus: function() {
                    this._element().focus()
                }
            });
        var processModules = function(that, modules) {
                var controllerTypes = {},
                    viewTypes = {};
                that._controllers = {};
                that._views = {};
                $.each(modules, function() {
                    var controllers = this.controllers,
                        moduleName = this.name,
                        views = this.views;
                    controllers && $.each(controllers, function(name, type) {
                        if (controllerTypes[name])
                            throw'Module "' + moduleName + '". Controller "' + name + '" is already registered';
                        else if (!(type && type.subclassOf && type.subclassOf(Controller))) {
                            type.subclassOf(Controller);
                            throw'Module "' + moduleName + '". Controller "' + name + '" must be inheritor of DevExpress.ui.dataGrid.Controller';
                        }
                        controllerTypes[name] = type
                    });
                    views && $.each(views, function(name, type) {
                        if (viewTypes[name])
                            throw'Module "' + moduleName + '". View "' + name + '" is already registered';
                        else if (!(type && type.subclassOf && type.subclassOf(View)))
                            throw'Module "' + moduleName + '". View "' + name + '" must be inheritor of DevExpress.ui.dataGrid.View';
                        viewTypes[name] = type
                    })
                });
                $.each(modules, function() {
                    var extenders = this.extenders;
                    if (extenders) {
                        extenders.controllers && $.each(extenders.controllers, function(name, extender) {
                            if (controllerTypes[name])
                                controllerTypes[name] = controllerTypes[name].inherit(extender)
                        });
                        extenders.views && $.each(extenders.views, function(name, extender) {
                            if (viewTypes[name])
                                viewTypes[name] = viewTypes[name].inherit(extender)
                        })
                    }
                });
                var registerPublicMethods = function(that, name, moduleItem) {
                        var publicMethods = moduleItem.publicMethods();
                        if (publicMethods)
                            $.each(publicMethods, function(index, methodName) {
                                if (moduleItem[methodName])
                                    if (!that[methodName])
                                        that[methodName] = function() {
                                            return moduleItem[methodName].apply(moduleItem, arguments)
                                        };
                                    else
                                        throw'Public method "' + methodName + '" is already registered';
                                else
                                    throw'Public method "' + name + '.' + methodName + '" is not exists';
                            })
                    };
                $.each(controllerTypes, function(name, controllerType) {
                    var controller = new controllerType(that);
                    controller.name = name;
                    registerPublicMethods(that, name, controller);
                    that._controllers[name] = controller
                });
                $.each(viewTypes, function(name, viewType) {
                    var view = new viewType(that);
                    view.name = name;
                    registerPublicMethods(that, name, view);
                    that._views[name] = view
                })
            };
        var dataGrid = ui.dataGrid = {
                __internals: {},
                modules: [],
                View: View,
                ViewController: ViewController,
                Controller: Controller,
                registerModule: function(name, module) {
                    var modules = this.modules,
                        i;
                    for (i = 0; i < modules.length; i++)
                        if (modules[i].name === name)
                            return;
                    module.name = name;
                    modules.push(module)
                },
                unregisterModule: function(name) {
                    this.modules = $.grep(this.modules, function(module) {
                        return module.name !== name
                    })
                },
                processModules: processModules
            };
        DX.registerComponent("dxDataGrid", ui.Widget.inherit(function() {
            return {
                    _deprecatedOptions: {"editing.texts.recoverRow": {
                            since: "14.1",
                            message: "Use the 'undeleteRow' option instead."
                        }},
                    _optionAliases: {"editing.texts.recoverRow": "editing.texts.undeleteRow"},
                    _setDefaultOptions: function() {
                        var that = this;
                        that.callBase();
                        $.each(dataGrid.modules, function() {
                            if ($.isFunction(this.defaultOptions))
                                that.option(this.defaultOptions())
                        })
                    },
                    _defaultOptionsRules: function() {
                        return this.callBase().slice(0).concat([{
                                    device: [{platform: "ios"}, {platform: "ios7"}],
                                    options: {showRowLines: true}
                                }, {
                                    device: function() {
                                        return DevExpress.browser.webkit
                                    },
                                    options: {loadPanel: {animation: {show: {
                                                    easing: 'cubic-bezier(1, 0, 1, 0)',
                                                    duration: 500,
                                                    from: {opacity: 0},
                                                    to: {opacity: 1}
                                                }}}}
                                }, {
                                    device: function() {
                                        return DX.devices.real().ios
                                    },
                                    options: {loadingTimeout: 30}
                                }])
                    },
                    _init: function() {
                        var that = this;
                        that.callBase();
                        processModules(that, dataGrid.modules);
                        $.each(that._controllers, function() {
                            this.init()
                        });
                        $.each(that._views, function() {
                            this.init()
                        });
                        that._gridView = that._views['gridView']
                    },
                    _clean: $.noop,
                    _optionChanged: function(name, value, prevValue) {
                        var that = this;
                        $.each(that._controllers, function() {
                            this.optionChanged(name, value, prevValue)
                        });
                        $.each(that._views, function() {
                            this.optionChanged(name, value, prevValue)
                        });
                        that.callBase(name, value, prevValue)
                    },
                    _dimensionChanged: function() {
                        this.resize()
                    },
                    _visibilityChanged: function() {
                        this.resize()
                    },
                    _renderContentImpl: function() {
                        var that = this;
                        that._gridView.render(that._element())
                    },
                    _renderContent: function() {
                        this._renderContentImpl()
                    },
                    _getTemplate: function(templateName) {
                        var template,
                            templateClass,
                            $template;
                        if (!this._templates[templateName]) {
                            $template = $(templateName);
                            if ($template.length === 1) {
                                templateClass = this._templateProvider.getTemplateClass();
                                this._templates[templateName] = new templateClass($template)
                            }
                        }
                        return this.callBase(templateName)
                    },
                    _dispose: function() {
                        var that = this;
                        that.callBase();
                        $.each(that._controllers, function() {
                            this.dispose()
                        });
                        $.each(that._views, function() {
                            this.dispose()
                        })
                    },
                    getController: function(name) {
                        return this._controllers[name]
                    },
                    getView: function(name) {
                        return this._views[name]
                    },
                    resize: function() {
                        this._gridView.resize()
                    }
                }
        }()))
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.groupingHelperBase.js */
    (function($, DX) {
        var normalizeSortingInfo = DX.data.utils.normalizeSortingInfo;
        DX.ui.dataGrid.GroupingHelperBase = DX.Class.inherit(function() {
            var findGroupInfoByKey = function(groupsInfo, key) {
                    var i;
                    for (i = 0; i < groupsInfo.length; i++)
                        if (DX.data.utils.keysEqual(null, groupsInfo[i].key, key))
                            return groupsInfo[i]
                };
            var getGroupInfoIndexByOffset = function(groupsInfo, offset) {
                    var index;
                    for (index = 0; index < groupsInfo.length; index++)
                        if (groupsInfo[index].offset > offset)
                            break;
                    return index
                };
            var updateGroupInfoOffsets = function(groupsInfo) {
                    var groupInfo,
                        index,
                        newIndex;
                    for (index = 0; index < groupsInfo.length; index++) {
                        groupInfo = groupsInfo[index];
                        if (groupInfo.data && groupInfo.data.offset !== groupInfo.offset) {
                            groupsInfo.splice(index, 1);
                            groupInfo.offset = groupInfo.data.offset;
                            newIndex = getGroupInfoIndexByOffset(groupsInfo, groupInfo.offset);
                            groupsInfo.splice(newIndex, 0, groupInfo);
                            if (newIndex > index)
                                index--
                        }
                    }
                };
            var cleanGroupsInfo = function(groupsInfo, groupIndex, groupsCount) {
                    var i;
                    for (i = 0; i < groupsInfo.length; i++)
                        if (groupIndex + 1 >= groupsCount)
                            groupsInfo[i].children = [];
                        else
                            cleanGroupsInfo(groupsInfo[i].children, groupIndex + 1, groupsCount)
                };
            return {
                    ctor: function(dataSource) {
                        this._dataSource = dataSource;
                        this.reset()
                    },
                    reset: function() {
                        this._groupsInfo = [];
                        this._totalCountCorrection = 0
                    },
                    totalItemsCount: function() {
                        var that = this,
                            totalCount = that._dataSource.totalCount();
                        return totalCount > 0 ? totalCount + that._totalCountCorrection : 0
                    },
                    itemsCount: function() {
                        return this._itemsCount || 0
                    },
                    mergeLoadedData: function(datas, groupDataOptions) {
                        var data = this.mergeLoadedDataCore(datas, groupDataOptions);
                        this._itemsCount = this.calculateItemsCount(data);
                        return data
                    },
                    updateTotalItemsCount: function(totalCountCorrection) {
                        this._totalCountCorrection = totalCountCorrection || 0
                    },
                    _isGroupItemCountable: function(item) {
                        return !this._isVirtualPaging() || !item.isContinuation
                    },
                    _isVirtualPaging: function() {
                        var dataSource = this._dataSource,
                            dataSourceOptions = dataSource && dataSource._options,
                            scrollingMode = dataSourceOptions && dataSourceOptions.scrolling && dataSourceOptions.scrolling.mode;
                        return scrollingMode === 'virtual' || scrollingMode === 'infinite'
                    },
                    updateItemsCount: function(data, groupsCount) {
                        function calculateItemsCount(that, items, groupsCount) {
                            var i,
                                result = 0;
                            if (items)
                                if (!groupsCount)
                                    result = items.length;
                                else
                                    for (i = 0; i < items.length; i++) {
                                        if (that._isGroupItemCountable(items[i]))
                                            result++;
                                        result += calculateItemsCount(that, items[i].items, groupsCount - 1)
                                    }
                            return result
                        }
                        this._itemsCount = calculateItemsCount(this, data, groupsCount)
                    },
                    foreachGroups: function(callback, childrenAtFirst) {
                        var that = this;
                        function foreachGroupsCore(groupsInfo, callback, childrenAtFirst, parents) {
                            var i,
                                callbackResult,
                                callbackResults = [];
                            function executeCallback(callback, data, parents, callbackResults) {
                                var callbackResult = data && callback(data, parents);
                                callbackResults.push(callbackResult);
                                return callbackResult
                            }
                            for (i = 0; i < groupsInfo.length; i++) {
                                parents.push(groupsInfo[i].data);
                                if (!childrenAtFirst && executeCallback(callback, groupsInfo[i].data, parents, callbackResults) === false)
                                    return false;
                                if (!groupsInfo[i].data || groupsInfo[i].data.isExpanded) {
                                    callbackResult = foreachGroupsCore(groupsInfo[i].children, callback, childrenAtFirst, parents);
                                    callbackResults.push(callbackResult);
                                    if (callbackResult === false)
                                        return false
                                }
                                if (childrenAtFirst && executeCallback(callback, groupsInfo[i].data, parents, callbackResults) === false)
                                    return false;
                                parents.pop()
                            }
                            return $.when.apply($, callbackResults).always(function() {
                                    updateGroupInfoOffsets(groupsInfo)
                                })
                        }
                        return foreachGroupsCore(that._groupsInfo, callback, childrenAtFirst, [])
                    },
                    findGroupInfo: function(path) {
                        var that = this,
                            i,
                            pathIndex,
                            groupInfo,
                            groupsInfo = that._groupsInfo;
                        for (pathIndex = 0; groupsInfo && pathIndex < path.length; pathIndex++) {
                            groupInfo = findGroupInfoByKey(groupsInfo, path[pathIndex]);
                            groupsInfo = groupInfo && groupInfo.children
                        }
                        return groupInfo && groupInfo.data
                    },
                    addGroupInfo: function(groupInfoData) {
                        var that = this,
                            index,
                            groupInfo,
                            path = groupInfoData.path,
                            pathIndex,
                            groupsInfo = that._groupsInfo;
                        for (pathIndex = 0; pathIndex < path.length; pathIndex++) {
                            groupInfo = findGroupInfoByKey(groupsInfo, path[pathIndex]);
                            if (!groupInfo) {
                                groupInfo = {
                                    key: path[pathIndex],
                                    offset: groupInfoData.offset,
                                    children: []
                                };
                                index = getGroupInfoIndexByOffset(groupsInfo, groupInfoData.offset);
                                groupsInfo.splice(index, 0, groupInfo)
                            }
                            if (pathIndex === path.length - 1) {
                                groupInfo.data = groupInfoData;
                                updateGroupInfoOffsets(groupsInfo)
                            }
                            groupsInfo = groupInfo.children
                        }
                    },
                    allowCollapseAll: function() {
                        return true
                    },
                    collapseAll: function(groupIndex) {
                        if (!this.allowCollapseAll())
                            return false;
                        return this._collapseExpandAll(groupIndex, false)
                    },
                    expandAll: function(groupIndex) {
                        return this._collapseExpandAll(groupIndex, true)
                    },
                    _collapseExpandAll: function(groupIndex, isExpand) {
                        var that = this,
                            dataSource = that._dataSource,
                            group = dataSource.group(),
                            groups = normalizeSortingInfo(group || []),
                            i;
                        if (groups.length) {
                            for (i = 0; i < groups.length; i++)
                                if (groupIndex === undefined || groupIndex === i)
                                    groups[i].isExpanded = isExpand;
                                else if (group && group[i])
                                    groups[i].isExpanded = group[i].isExpanded;
                            dataSource.group(groups);
                            that.foreachGroups(function(groupInfo, parents) {
                                if (groupIndex === undefined || groupIndex === parents.length - 1)
                                    groupInfo.isExpanded = isExpand
                            });
                            that.updateItemsCount()
                        }
                        return true
                    },
                    processLoadOptions: function(storeLoadOptions) {
                        this._group = storeLoadOptions.group
                    },
                    refresh: function(storeLoadOptions) {
                        var that = this,
                            groupIndex,
                            oldGroups = normalizeSortingInfo(that._group || []),
                            groups = normalizeSortingInfo(storeLoadOptions.group || []),
                            groupsCount = Math.min(oldGroups.length, groups.length);
                        that._group = storeLoadOptions.group;
                        for (groupIndex = 0; groupIndex < groupsCount; groupIndex++)
                            if (oldGroups[groupIndex].selector !== groups[groupIndex].selector) {
                                groupsCount = groupIndex;
                                break
                            }
                        if (!groupsCount)
                            that.reset();
                        else
                            cleanGroupsInfo(that._groupsInfo, 0, groupsCount)
                    }
                }
        }())
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.groupingHelper.js */
    (function($, DX) {
        var utils = DX.utils,
            normalizeSortingInfo = DX.data.utils.normalizeSortingInfo,
            keysEqual = DX.data.utils.keysEqual;
        DX.ui.dataGrid.GroupingHelper = DX.ui.dataGrid.GroupingHelperBase.inherit(function() {
            var foreachCollapsedGroups = function(that, callback) {
                    return that.foreachGroups(function(groupInfo) {
                            if (!groupInfo.isExpanded)
                                return callback(groupInfo)
                        })
                };
            var correctSkipLoadOption = function(that, skip) {
                    var skipCorrection = 0,
                        resultSkip = skip || 0;
                    if (skip) {
                        foreachCollapsedGroups(that, function(groupInfo) {
                            if (groupInfo.offset - skipCorrection >= skip)
                                return false;
                            skipCorrection += groupInfo.count - 1
                        });
                        resultSkip += skipCorrection
                    }
                    return resultSkip
                };
            var processGroupItems = function(that, items, path, offset, skipFirstItem, take) {
                    var i,
                        item,
                        offsetInfo,
                        removeLastItemsCount = 0,
                        needRemoveFirstItem = false;
                    for (i = 0; i < items.length; i++) {
                        item = items[i];
                        if (utils.isDefined(item.key) && utils.isDefined(item.items)) {
                            path.push(item.key);
                            var groupInfo = that.findGroupInfo(path);
                            if (groupInfo && !groupInfo.isExpanded) {
                                item.items = null;
                                offset += groupInfo.count;
                                take--;
                                if (take < 0)
                                    removeLastItemsCount++;
                                if (skipFirstItem)
                                    needRemoveFirstItem = true
                            }
                            else {
                                offsetInfo = processGroupItems(that, item.items, path, offset, skipFirstItem, take);
                                if (skipFirstItem)
                                    if (offsetInfo.offset - offset > 1)
                                        item.isContinuation = true;
                                    else
                                        needRemoveFirstItem = true;
                                offset = offsetInfo.offset;
                                take = offsetInfo.take;
                                if (take < 0)
                                    if (item.items.length)
                                        item.isContinuationOnNextPage = true;
                                    else
                                        removeLastItemsCount++
                            }
                            path.pop()
                        }
                        else {
                            if (skipFirstItem)
                                needRemoveFirstItem = true;
                            offset++;
                            take--;
                            if (take < 0)
                                removeLastItemsCount++
                        }
                        skipFirstItem = false
                    }
                    if (needRemoveFirstItem)
                        items.splice(0, 1);
                    if (removeLastItemsCount)
                        items.splice(-removeLastItemsCount, removeLastItemsCount);
                    return {
                            offset: offset,
                            take: take
                        }
                };
            var pathEquals = function(path1, path2) {
                    var i;
                    if (path1.length !== path2.length)
                        return false;
                    for (i = 0; i < path1.length; i++)
                        if (!keysEqual(null, path1[i], path2[i]))
                            return false;
                    return true
                };
            var updateGroupOffsets = function(that, items, path, offset, additionalGroupInfo) {
                    var i,
                        item,
                        groupsInfo = that._groupsInfo;
                    for (i = 0; i < items.length; i++) {
                        item = items[i];
                        if (item.key !== undefined && item.items !== undefined) {
                            path.push(item.key);
                            if (additionalGroupInfo && pathEquals(additionalGroupInfo.path, path))
                                additionalGroupInfo.offset = offset;
                            var groupInfo = that.findGroupInfo(path);
                            if (groupInfo && !groupInfo.isExpanded) {
                                groupInfo.offset = offset;
                                offset += groupInfo.count
                            }
                            else
                                offset = updateGroupOffsets(that, item.items, path, offset, additionalGroupInfo);
                            path.pop()
                        }
                        else
                            offset++
                    }
                    return offset
                };
            var removeGroupLoadOption = function(storeLoadOptions) {
                    if (storeLoadOptions.group) {
                        storeLoadOptions.sort = normalizeSortingInfo(storeLoadOptions.group || []).concat(normalizeSortingInfo(storeLoadOptions.sort || []));
                        delete storeLoadOptions.group
                    }
                };
            var createGroupFilter = function(path, storeLoadOptions) {
                    var groups = normalizeSortingInfo(storeLoadOptions.group || []),
                        i,
                        filter = [];
                    for (i = 0; i < path.length; i++)
                        filter.push([groups[i].selector, '=', path[i]]);
                    if (storeLoadOptions.filter)
                        filter.push(storeLoadOptions.filter);
                    return filter
                };
            var createOffsetFilter = function(path, storeLoadOptions) {
                    var groups = normalizeSortingInfo(storeLoadOptions.group || []),
                        i,
                        j,
                        filterElement,
                        filter = [];
                    for (i = 0; i < path.length; i++) {
                        filterElement = [];
                        for (j = 0; j <= i; j++)
                            filterElement.push([groups[j].selector, i === j ? groups[j].desc ? '>' : '<' : '=', path[j]]);
                        if (filter.length)
                            filter.push('or');
                        filter.push(filterElement)
                    }
                    if (storeLoadOptions.filter)
                        filter.push(storeLoadOptions.filter);
                    return filter
                };
            return {
                    processLoadOptions: function(storeLoadOptions) {
                        var that = this,
                            currentTake,
                            loadOptions,
                            collapsedPaths = [],
                            collapsedPathsByLoads = [],
                            skipFirstItem = false,
                            take,
                            offset,
                            group = storeLoadOptions.group,
                            groupLoadOptions = [];
                        that.callBase(storeLoadOptions);
                        removeGroupLoadOption(storeLoadOptions);
                        loadOptions = $.extend({}, storeLoadOptions);
                        loadOptions.skip = correctSkipLoadOption(that, storeLoadOptions.skip);
                        if (loadOptions.skip && loadOptions.take && group) {
                            loadOptions.skip--;
                            loadOptions.take++;
                            skipFirstItem = true
                        }
                        if (loadOptions.take && group) {
                            take = loadOptions.take;
                            loadOptions.take++
                        }
                        offset = loadOptions.skip || 0;
                        if (loadOptions.take) {
                            foreachCollapsedGroups(that, function(groupInfo) {
                                if (groupInfo.offset >= loadOptions.skip + loadOptions.take)
                                    return false;
                                else if (groupInfo.offset >= loadOptions.skip && groupInfo.count) {
                                    currentTake = groupInfo.offset - loadOptions.skip;
                                    if (currentTake > 0) {
                                        groupLoadOptions.push($.extend({}, loadOptions, {
                                            skip: loadOptions.skip,
                                            take: currentTake
                                        }));
                                        loadOptions.take -= currentTake;
                                        collapsedPathsByLoads.push(collapsedPaths);
                                        collapsedPaths = []
                                    }
                                    loadOptions.skip = groupInfo.offset + groupInfo.count;
                                    loadOptions.take--;
                                    collapsedPaths.push(groupInfo.path)
                                }
                            });
                            if (!groupLoadOptions.length || loadOptions.take > 0)
                                groupLoadOptions.push(loadOptions);
                            if (collapsedPaths.length)
                                collapsedPathsByLoads.push(collapsedPaths)
                        }
                        else
                            groupLoadOptions.push(loadOptions);
                        return {
                                loads: groupLoadOptions,
                                data: {
                                    collapsedPathsByLoads: collapsedPathsByLoads,
                                    offset: offset,
                                    skipFirstItem: skipFirstItem,
                                    take: take,
                                    group: group
                                }
                            }
                    },
                    updateTotalItemsCount: function() {
                        var itemsCountCorrection = 0;
                        foreachCollapsedGroups(this, function(groupInfo) {
                            if (groupInfo.count)
                                itemsCountCorrection -= groupInfo.count - 1
                        });
                        this.callBase(itemsCountCorrection)
                    },
                    changeGroupExpand: function(path) {
                        var that = this,
                            dataSource = that._dataSource,
                            basePageIndex = dataSource.basePageIndex && dataSource.basePageIndex() || dataSource.pageIndex(),
                            offset = correctSkipLoadOption(that, basePageIndex * dataSource.pageSize()),
                            groupCountQuery;
                        groupCountQuery = dataSource.store().totalCount({filter: createGroupFilter(path, {
                                filter: dataSource.filter(),
                                group: dataSource.group()
                            })});
                        return $.when(groupCountQuery).done(function(count) {
                                var groupInfo;
                                count = parseInt(count.length ? count[0] : count);
                                groupInfo = that.findGroupInfo(path);
                                if (groupInfo) {
                                    updateGroupOffsets(that, dataSource.items(), [], offset);
                                    groupInfo.isExpanded = !groupInfo.isExpanded;
                                    groupInfo.count = count
                                }
                                else {
                                    groupInfo = {
                                        offset: -1,
                                        count: count,
                                        path: path,
                                        isExpanded: false
                                    };
                                    updateGroupOffsets(that, dataSource.items(), [], offset, groupInfo);
                                    if (groupInfo.offset >= 0)
                                        that.addGroupInfo(groupInfo)
                                }
                                that.updateTotalItemsCount()
                            }).fail($.proxy(dataSource.loadError.fire, dataSource.loadError))
                    },
                    mergeLoadedData: function(datas, groupDataOptions) {
                        var that = this,
                            data = [],
                            i,
                            pathIndex,
                            query,
                            collapsedPathsByLoads = groupDataOptions.collapsedPathsByLoads,
                            collapsedPaths,
                            groups = normalizeSortingInfo(groupDataOptions.group || []),
                            groupsCount = groups.length,
                            loadsCount = Math.max(datas.length, collapsedPathsByLoads.length);
                        function createCollapsedGroupItem(path) {
                            var result = {},
                                i,
                                item;
                            for (i = 0; i < path.length; i++) {
                                if (!item)
                                    item = result;
                                else {
                                    item.items.push({});
                                    item = item.items[0]
                                }
                                item.key = path[i];
                                item.items = []
                            }
                            return result
                        }
                        function appendData(data, appendingData) {
                            var index = 0;
                            if (appendingData) {
                                if (data.length && appendingData.length && keysEqual(null, data[data.length - 1].key, appendingData[0].key)) {
                                    appendData(data[data.length - 1].items, appendingData[0].items);
                                    index = 1
                                }
                                while (index < appendingData.length) {
                                    data.push(appendingData[index]);
                                    index++
                                }
                            }
                        }
                        for (i = 0; i < loadsCount; i++) {
                            collapsedPaths = collapsedPathsByLoads[i];
                            if (collapsedPaths && collapsedPaths.length)
                                for (pathIndex = 0; pathIndex < collapsedPaths.length; pathIndex++)
                                    appendData(data, [createCollapsedGroupItem(collapsedPaths[pathIndex])]);
                            if (datas[i]) {
                                query = DX.data.query(datas[i]);
                                DX.data.utils.multiLevelGroup(query, groups).enumerate().done(function(groupedData) {
                                    appendData(data, groupedData)
                                })
                            }
                        }
                        processGroupItems(that, data, [], groupDataOptions.offset, groupDataOptions.skipFirstItem, groupDataOptions.take);
                        that.updateItemsCount(data, groupsCount);
                        return data
                    },
                    allowCollapseAll: function() {
                        return false
                    },
                    refresh: function(storeLoadOptions) {
                        var that = this,
                            store = that._dataSource.store();
                        that.callBase(storeLoadOptions);
                        return foreachCollapsedGroups(that, function(groupInfo) {
                                var groupCountQuery = store.totalCount({filter: createGroupFilter(groupInfo.path, storeLoadOptions)}),
                                    groupOffsetQuery = store.totalCount({filter: createOffsetFilter(groupInfo.path, storeLoadOptions)});
                                return $.when(groupOffsetQuery, groupCountQuery).done(function(offset, count) {
                                        offset = parseInt(offset.length ? offset[0] : offset);
                                        count = parseInt(count.length ? count[0] : count);
                                        groupInfo.offset = offset;
                                        if (groupInfo.count !== count) {
                                            groupInfo.count = count;
                                            that.updateTotalItemsCount()
                                        }
                                    }).fail($.proxy(that._dataSource.loadError.fire, that._dataSource.loadError))
                            })
                    }
                }
        }())
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.groupingHelperWithNativeGrouping.js */
    (function($, DX) {
        var utils = DX.utils,
            normalizeSortingInfo = DX.data.utils.normalizeSortingInfo,
            keysEqual = DX.data.utils.keysEqual;
        DX.ui.dataGrid.GroupingHelperWithNativeGrouping = DX.ui.dataGrid.GroupingHelperBase.inherit(function() {
            var foreachExpandedGroups = function(that, callback) {
                    return that.foreachGroups(function(groupInfo, parents) {
                            if (groupInfo.isExpanded)
                                return callback(groupInfo, parents)
                        }, true)
                };
            var processGroupItems = function(that, items, path, groupsCount) {
                    var i,
                        item;
                    if (!groupsCount)
                        return;
                    for (i = 0; i < items.length; i++) {
                        item = items[i];
                        if (item.key != undefined && item.items != undefined) {
                            path.push(item.key);
                            var groupInfo = that.findGroupInfo(path);
                            if (!groupInfo || !groupInfo.isExpanded)
                                item.items = null;
                            else
                                processGroupItems(that, item.items, path, groupsCount - 1);
                            path.pop()
                        }
                    }
                };
            var hasExpandedGroup = function(that, group) {
                    var hasExpandedGroup = false,
                        i,
                        groupsCount = normalizeSortingInfo(group || []).length;
                    for (i = 0; i < groupsCount; i++)
                        if (that._isGroupExpanded(i))
                            hasExpandedGroup = true;
                    return hasExpandedGroup
                };
            var updateGroupInfos = function(that, items, groupsCount, offset) {
                    updateGroupInfosCore(that, items, 0, groupsCount, [], offset)
                };
            var updateGroupInfosCore = function(that, items, groupIndex, groupsCount, path, offset) {
                    var item,
                        i,
                        groupInfo;
                    if (groupIndex >= groupsCount)
                        return;
                    for (i = 0; i < items.length; i++) {
                        item = items[i];
                        if (item) {
                            path.push(item.key);
                            groupInfo = that.findGroupInfo(path);
                            if (!groupInfo)
                                that.addGroupInfo({
                                    isExpanded: that._isGroupExpanded(groupIndex),
                                    path: path.slice(0),
                                    offset: offset + i,
                                    count: item.items.length
                                });
                            else {
                                groupInfo.count = item.items.length;
                                groupInfo.offset = offset + i
                            }
                            updateGroupInfosCore(that, item.items, groupIndex + 1, groupsCount, path, 0);
                            path.pop()
                        }
                    }
                };
            var isGroupExpanded = function(groups, groupIndex) {
                    return groups && groups.length && groups[groupIndex] && !!groups[groupIndex].isExpanded
                };
            var getTotalOffset = function(groupInfos, pageSize, offset) {
                    var groupIndex,
                        prevOffset = 0,
                        groupSize,
                        totalOffset = offset;
                    for (groupIndex = 0; groupIndex < groupInfos.length; groupIndex++) {
                        groupSize = groupInfos[groupIndex].offset + 1;
                        if (groupIndex > 0) {
                            groupSize += groupInfos[groupIndex - 1].childrenTotalCount;
                            if (pageSize)
                                groupSize += getContinuationGroupCount(totalOffset, pageSize, groupSize, groupIndex - 1) * groupIndex
                        }
                        totalOffset += groupSize
                    }
                    return totalOffset
                };
            var getContinuationGroupCount = function(groupOffset, pageSize, groupSize, groupIndex) {
                    groupIndex = groupIndex || 0;
                    if (pageSize > 1 && groupSize > 0) {
                        var pageOffset = groupOffset - Math.floor(groupOffset / pageSize) * pageSize || pageSize;
                        pageOffset += groupSize - groupIndex - 2;
                        if (pageOffset < 0)
                            pageOffset += pageSize;
                        return Math.floor(pageOffset / (pageSize - groupIndex - 1))
                    }
                    return 0
                };
            DX.ui.dataGrid.getContinuationGroupCount = getContinuationGroupCount;
            return {
                    updateTotalItemsCount: function() {
                        var totalItemsCount = 0,
                            pageSize = this._dataSource.pageSize(),
                            isVirtualPaging = this._isVirtualPaging();
                        foreachExpandedGroups(this, function(groupInfo, parents) {
                            groupInfo.childrenTotalCount = 0
                        });
                        foreachExpandedGroups(this, function(groupInfo, parents) {
                            var totalOffset = getTotalOffset(parents, isVirtualPaging ? 0 : pageSize, totalItemsCount),
                                count = groupInfo.count + groupInfo.childrenTotalCount,
                                i;
                            if (!isVirtualPaging)
                                count += getContinuationGroupCount(totalOffset, pageSize, count, parents.length - 1);
                            if (parents[parents.length - 2])
                                parents[parents.length - 2].childrenTotalCount += count;
                            else
                                totalItemsCount += count
                        });
                        this.callBase(totalItemsCount)
                    },
                    _isGroupExpanded: function(groupIndex) {
                        var groups = this._dataSource.group();
                        return isGroupExpanded(groups, groupIndex)
                    },
                    processLoadOptions: function(storeLoadOptions, isExpandedGroupsLoaded) {
                        var that = this,
                            dataSource = this._dataSource,
                            isVirtualPaging = that._isVirtualPaging(),
                            pageSize = dataSource.pageSize(),
                            groups = normalizeSortingInfo(storeLoadOptions.group || []),
                            skips = [],
                            takes = [],
                            skipChildrenTotalCount = 0,
                            childrenTotalCount = 0,
                            loadOptions = $.extend({}, storeLoadOptions);
                        that.callBase(storeLoadOptions);
                        if (hasExpandedGroup(that, groups) && !isExpandedGroupsLoaded) {
                            delete loadOptions.skip;
                            delete loadOptions.take
                        }
                        else if (loadOptions.take) {
                            foreachExpandedGroups(this, function(groupInfo) {
                                groupInfo.childrenTotalCount = 0;
                                groupInfo.skipChildrenTotalCount = 0
                            });
                            foreachExpandedGroups(that, function(groupInfo, parents) {
                                var skip,
                                    take,
                                    takeCorrection = 0,
                                    parentTakeCorrection = 0,
                                    totalOffset = getTotalOffset(parents, isVirtualPaging ? 0 : pageSize, childrenTotalCount),
                                    continuationGroupCount = 0,
                                    skipContinuationGroupCount = 0,
                                    groupInfoCount = groupInfo.count + groupInfo.childrenTotalCount,
                                    childrenGroupInfoCount = groupInfoCount;
                                if (totalOffset <= loadOptions.skip + loadOptions.take && groupInfoCount) {
                                    skip = loadOptions.skip - totalOffset;
                                    take = loadOptions.take;
                                    if (!isVirtualPaging) {
                                        continuationGroupCount = getContinuationGroupCount(totalOffset, pageSize, groupInfoCount, parents.length - 1);
                                        groupInfoCount += continuationGroupCount * parents.length;
                                        childrenGroupInfoCount += continuationGroupCount;
                                        if (pageSize && skip >= 0) {
                                            takeCorrection = parents.length;
                                            parentTakeCorrection = parents.length - 1;
                                            skipContinuationGroupCount = Math.floor(skip / pageSize)
                                        }
                                    }
                                    if (skip >= 0) {
                                        if (totalOffset + groupInfoCount > loadOptions.skip)
                                            skips.unshift(skip - skipContinuationGroupCount * takeCorrection - groupInfo.skipChildrenTotalCount);
                                        if (totalOffset + groupInfoCount >= loadOptions.skip + take)
                                            takes.unshift(take - takeCorrection - groupInfo.childrenTotalCount + groupInfo.skipChildrenTotalCount)
                                    }
                                    else if (totalOffset + groupInfoCount >= loadOptions.skip + take)
                                        takes.unshift(take + skip - groupInfo.childrenTotalCount)
                                }
                                if (totalOffset <= loadOptions.skip)
                                    if (parents[parents.length - 2])
                                        parents[parents.length - 2].skipChildrenTotalCount += Math.min(childrenGroupInfoCount, skip + 1 - skipContinuationGroupCount * parentTakeCorrection);
                                    else
                                        skipChildrenTotalCount += Math.min(childrenGroupInfoCount, skip + 1);
                                if (totalOffset <= loadOptions.skip + take) {
                                    groupInfoCount = Math.min(childrenGroupInfoCount, skip + take - (skipContinuationGroupCount + 1) * parentTakeCorrection);
                                    if (parents[parents.length - 2])
                                        parents[parents.length - 2].childrenTotalCount += groupInfoCount;
                                    else
                                        childrenTotalCount += groupInfoCount
                                }
                            });
                            loadOptions.skip -= skipChildrenTotalCount;
                            loadOptions.take -= childrenTotalCount - skipChildrenTotalCount
                        }
                        return {
                                loads: [loadOptions],
                                data: {
                                    skip: loadOptions.skip,
                                    take: loadOptions.take,
                                    skips: skips,
                                    takes: takes,
                                    storeLoadOptions: storeLoadOptions
                                }
                            }
                    },
                    changeGroupExpand: function(path) {
                        var that = this,
                            groupInfo = that.findGroupInfo(path);
                        if (groupInfo) {
                            groupInfo.isExpanded = !groupInfo.isExpanded;
                            that.updateTotalItemsCount();
                            return $.Deferred().resolve()
                        }
                        return $.Deferred().reject()
                    },
                    mergeLoadedData: function(datas, groupDataOptions) {
                        var that = this,
                            data = datas[0],
                            group = normalizeSortingInfo(groupDataOptions.storeLoadOptions.group || []),
                            groupsCount = group.length,
                            skips,
                            takes,
                            i,
                            item,
                            items;
                        updateGroupInfos(that, data, groupsCount, groupDataOptions.skip || 0);
                        that.updateTotalItemsCount();
                        if (hasExpandedGroup(that, group)) {
                            groupDataOptions = that.processLoadOptions(groupDataOptions.storeLoadOptions, true).data;
                            if (groupDataOptions.skip)
                                data = data.slice(groupDataOptions.skip);
                            if (groupDataOptions.take)
                                data = data.slice(0, groupDataOptions.take)
                        }
                        skips = groupDataOptions.skips;
                        takes = groupDataOptions.takes;
                        items = data;
                        for (i = 0; items && i < groupsCount; i++) {
                            item = items[0];
                            items = item && item.items;
                            if (items && skips[i] !== undefined) {
                                item.isContinuation = true;
                                items = items.slice(skips[i]);
                                item.items = items
                            }
                        }
                        items = data;
                        for (i = 0; items && i < groupsCount; i++) {
                            item = items[items.length - 1];
                            items = item && item.items;
                            if (items && takes[i] !== undefined && items.length > takes[i]) {
                                item.isContinuationOnNextPage = true;
                                items = items.slice(0, takes[i]);
                                item.items = items
                            }
                        }
                        processGroupItems(that, data, [], groupsCount);
                        that.updateItemsCount(data, groupsCount);
                        return data
                    },
                    refresh: function(storeLoadOptions) {
                        var that = this,
                            oldGroups = normalizeSortingInfo(that._group || []),
                            groups = normalizeSortingInfo(storeLoadOptions.group || []),
                            groupIndex;
                        for (groupIndex = 0; groupIndex < oldGroups.length; groupIndex++)
                            if (isGroupExpanded(that._group, groupIndex) !== isGroupExpanded(storeLoadOptions.group, groupIndex)) {
                                that.reset();
                                return
                            }
                        that.callBase(storeLoadOptions);
                        that.foreachGroups(function(groupInfo) {
                            groupInfo.count = 0
                        });
                        if (groups.length)
                            return that._dataSource.store().load(storeLoadOptions).done(function(data) {
                                    updateGroupInfos(that, data, groups.length, 0)
                                }).fail($.proxy(that._dataSource.loadError.fire, that._dataSource.loadError))
                    }
                }
        }())
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.scrollingDataSourceWrapper.js */
    (function($, DX) {
        var dataGrid = DX.ui.dataGrid,
            utils = DX.utils;
        dataGrid.ScrollingDataSourceWrapper = DX.Class.inherit(function() {
            var getPreloadPageCount = function(that) {
                    var scrolling = that._options.scrolling;
                    return scrolling && scrolling.preloadEnabled ? 2 : 1
                };
            var isVirtualMode = function(that) {
                    return that._options.scrolling && that._options.scrolling.mode === 'virtual'
                };
            var isAppendMode = function(that) {
                    return that._options.scrolling && that._options.scrolling.mode === 'infinite'
                };
            var getBasePageIndex = function(that) {
                    return that._cache[0] ? that._cache[0].pageIndex : -1
                };
            var updateLoading = function(that) {
                    var basePageIndex = getBasePageIndex(that),
                        pagesCount = that._cache.length;
                    if (isVirtualMode(that))
                        if (basePageIndex < 0 || that._viewportItemIndex >= 0 && (basePageIndex * that.pageSize() > that._viewportItemIndex || basePageIndex * that.pageSize() + that.itemsCount() < that._viewportItemIndex + that._viewportSize) && that._dataSource.isLoading()) {
                            if (!that._isLoading) {
                                that._isLoading = true;
                                that.loadingChanged.fire(true)
                            }
                        }
                        else if (that._isLoading) {
                            that._isLoading = false;
                            that.loadingChanged.fire(false)
                        }
                };
            return {
                    ctor: function(options) {
                        var that = this,
                            dataSource = new dataGrid.DataSource(options, that);
                        that._dataSource = dataSource;
                        that.loadError = dataSource.loadError;
                        that.changed = $.Callbacks();
                        that.loadingChanged = $.Callbacks();
                        that._isLoading = true;
                        that._pageIndex = dataSource.pageIndex();
                        that._lastPageIndex = that._pageIndex;
                        that._viewportSize = 0;
                        that._viewportItemIndex = -1;
                        that._userPageSize = options.pageSize;
                        that._items = [];
                        dataSource.loadingChanged.add(function(isLoading) {
                            if (!isVirtualMode(that)) {
                                that._isLoading = isLoading;
                                that.loadingChanged.fire(isLoading)
                            }
                        });
                        var processChanged = function(that, changeType, isDelayChanged) {
                                var dataSource = that._dataSource,
                                    items = dataSource.items();
                                if (changeType === 'append')
                                    that._items.push.apply(that._items, items);
                                else if (changeType === 'prepend')
                                    that._items.unshift.apply(that._items, items);
                                else
                                    that._items = items;
                                updateLoading(that);
                                that._lastPageIndex = that.pageIndex();
                                that._isDelayChanged = isDelayChanged;
                                if (!isDelayChanged)
                                    that.changed.fire(changeType && {
                                        changeType: changeType,
                                        items: items
                                    })
                            };
                        var processDelayChanged = function(that) {
                                if (that._isDelayChanged) {
                                    that._isDelayChanged = false;
                                    that.changed.fire()
                                }
                            };
                        dataSource.changed.add(function() {
                            var basePageIndex,
                                lastCacheLength = that._cache.length,
                                changeType,
                                cacheItem;
                            if (isVirtualMode(that)) {
                                basePageIndex = getBasePageIndex(that);
                                if (basePageIndex >= 0)
                                    if (basePageIndex + that._cache.length === dataSource.pageIndex());
                                    else if (basePageIndex - 1 === dataSource.pageIndex());
                                    else
                                        that._cache = [];
                                cacheItem = {
                                    pageIndex: dataSource.pageIndex(),
                                    itemsCount: dataSource.itemsCount()
                                };
                                processDelayChanged(that);
                                if (basePageIndex === dataSource.pageIndex() + 1) {
                                    changeType = 'prepend';
                                    that._cache.unshift(cacheItem)
                                }
                                else {
                                    changeType = 'append';
                                    that._cache.push(cacheItem)
                                }
                                processChanged(that, that._cache.length > 1 ? changeType : undefined, lastCacheLength === 0);
                                that.load().done(function() {
                                    processDelayChanged(that)
                                })
                            }
                            else
                                processChanged(that, isAppendMode(that) && dataSource.pageIndex() !== 0 ? 'append' : undefined)
                        });
                        $.each(dataSource, function(memberName, member) {
                            if (!that[memberName] && $.isFunction(member))
                                that[memberName] = function() {
                                    return this._dataSource[memberName].apply(this._dataSource, arguments)
                                }
                        });
                        that._cache = [];
                        that._options = options
                    },
                    items: function() {
                        return this._items
                    },
                    itemsCount: function() {
                        var itemsCount = 0;
                        if (isVirtualMode(this))
                            $.each(this._cache, function() {
                                itemsCount += this.itemsCount
                            });
                        else
                            itemsCount = this._dataSource.itemsCount();
                        return itemsCount
                    },
                    virtualItemsCount: function() {
                        var that = this,
                            pageIndex,
                            itemsCount = 0,
                            i,
                            beginItemsCount,
                            endItemsCount;
                        if (isVirtualMode(that)) {
                            pageIndex = getBasePageIndex(that);
                            if (pageIndex < 0)
                                pageIndex = 0;
                            beginItemsCount = pageIndex * that.pageSize();
                            itemsCount = that._cache.length * that.pageSize();
                            endItemsCount = Math.max(0, that.totalItemsCount() - itemsCount - beginItemsCount);
                            return {
                                    begin: beginItemsCount,
                                    end: endItemsCount
                                }
                        }
                    },
                    setViewportItemIndex: function(itemIndex) {
                        var that = this,
                            pageSize = that.pageSize(),
                            dataSource = that._dataSource,
                            pagesCount = that.pagesCount(),
                            virtualMode = isVirtualMode(that),
                            appendMode = isAppendMode(that),
                            totalItemsCount = that.totalItemsCount(),
                            lastPageSize,
                            needLoad = that._viewportItemIndex < 0,
                            maxPageIndex,
                            newPageIndex;
                        that._viewportItemIndex = itemIndex;
                        if (pageSize && (virtualMode || appendMode)) {
                            if (that._viewportSize && itemIndex + that._viewportSize >= totalItemsCount) {
                                if (that.hasKnownLastPage()) {
                                    newPageIndex = pagesCount - 1;
                                    lastPageSize = totalItemsCount % pageSize;
                                    if (newPageIndex > 0 && lastPageSize > 0 && lastPageSize < pageSize / 2)
                                        newPageIndex--
                                }
                                else if (that.pageIndex() < pagesCount)
                                    newPageIndex = pagesCount
                            }
                            else {
                                newPageIndex = Math.floor(itemIndex / pageSize);
                                maxPageIndex = pagesCount - 1;
                                newPageIndex = Math.max(newPageIndex, 0);
                                newPageIndex = Math.min(newPageIndex, maxPageIndex)
                            }
                            if (that.pageIndex() !== newPageIndex || needLoad) {
                                that.pageIndex(newPageIndex);
                                that.load()
                            }
                        }
                    },
                    setViewportSize: function(size) {
                        var that = this,
                            pageSize;
                        if (that._viewportSize !== size) {
                            that._viewportSize = size;
                            if ((isVirtualMode(that) || isAppendMode(that)) && !that._userPageSize) {
                                pageSize = Math.ceil(size / 5) * 10;
                                if (pageSize !== that.pageSize()) {
                                    that.pageSize(pageSize);
                                    that.reload()
                                }
                            }
                        }
                    },
                    pageIndex: function(pageIndex) {
                        if (isVirtualMode(this) || isAppendMode(this)) {
                            if (pageIndex !== undefined)
                                this._pageIndex = pageIndex;
                            return this._pageIndex
                        }
                        else
                            return this._dataSource.pageIndex(pageIndex)
                    },
                    basePageIndex: function() {
                        var basePageIndex = getBasePageIndex(this);
                        return basePageIndex > 0 ? basePageIndex : 0
                    },
                    load: function() {
                        var basePageIndex = getBasePageIndex(this),
                            pageIndexForLoad = -1,
                            dataSource = this._dataSource,
                            result;
                        var loadCore = function(that, pageIndex) {
                                var dataSource = that._dataSource;
                                if (pageIndex === that.pageIndex() || !dataSource.isLoading() && pageIndex < dataSource.pagesCount() || !dataSource.hasKnownLastPage() && pageIndex === dataSource.pagesCount()) {
                                    dataSource.pageIndex(pageIndex);
                                    return dataSource.load()
                                }
                            };
                        if (isVirtualMode(this)) {
                            if (basePageIndex < 0 || !this._cache[this._pageIndex - basePageIndex])
                                pageIndexForLoad = this._pageIndex;
                            if (basePageIndex >= 0 && pageIndexForLoad < 0 && this._viewportItemIndex >= 0 && basePageIndex + this._cache.length <= this._pageIndex + getPreloadPageCount(this))
                                pageIndexForLoad = basePageIndex + this._cache.length;
                            if (pageIndexForLoad >= 0)
                                result = loadCore(this, pageIndexForLoad);
                            updateLoading(this)
                        }
                        else if (isAppendMode(this)) {
                            if (!dataSource.isLoaded() || this.pageIndex() === dataSource.pagesCount()) {
                                dataSource.pageIndex(this.pageIndex());
                                result = dataSource.load()
                            }
                        }
                        else
                            result = dataSource.load();
                        if (!result && this._lastPageIndex !== this.pageIndex())
                            this.changed.fire({changeType: 'pageIndex'});
                        return result || $.Deferred().resolve()
                    },
                    isLoading: function() {
                        return this._isLoading
                    },
                    changeGroupExpand: function(path) {
                        this._cache = [];
                        updateLoading(this);
                        this._dataSource.changeGroupExpand(path)
                    },
                    reload: function() {
                        this._cache = [];
                        updateLoading(this);
                        if (isAppendMode(this)) {
                            this.pageIndex(0);
                            this._dataSource.pageIndex(0)
                        }
                        else
                            this._dataSource.pageIndex(this.pageIndex());
                        return this._dataSource.reload()
                    }
                }
        }())
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.dataSource.js */
    (function($, DX) {
        var dataGrid = DX.ui.dataGrid;
        dataGrid.DataSource = DX.data.DataSource.inherit(function() {
            var hasGrouping = function(that) {
                    return !!that._storeLoadOptions.group
                };
            return {
                    ctor: function(options, dataSourceWrapper) {
                        var that = this;
                        that.callBase(options);
                        that._pageIndex = options.pageIndex || 0;
                        that._asyncLoadEnabled = !!options.asyncLoadEnabled;
                        that._loadingTimeout = options.loadingTimeout;
                        if (options.useNativeGrouping === 'auto')
                            options.useNativeGrouping = that.store() instanceof DX.data.ArrayStore;
                        that._groupingHelper = options.useNativeGrouping ? new dataGrid.GroupingHelperWithNativeGrouping(dataSourceWrapper || that) : new dataGrid.GroupingHelper(dataSourceWrapper || that);
                        that._hasLastPage = false;
                        that._currentTotalCount = 0;
                        that._options = options;
                        that.map(that._mapFunc)
                    },
                    map: function(mapFunc) {
                        var that = this,
                            i,
                            store = that.store();
                        if (mapFunc)
                            if (store instanceof DX.data.ArrayStore) {
                                for (i = 0; i < store._array.length; i++)
                                    store._array[i] = mapFunc(store._array[i]);
                                delete that._mapFunc
                            }
                            else
                                that._mapFunc = mapFunc;
                        else
                            return that._mapFunc
                    },
                    pageSize: function(value) {
                        if (value === undefined)
                            return this._paginate ? this._pageSize : 0;
                        this._pageSize = value || 20
                    },
                    totalCount: function() {
                        return parseInt(this._currentTotalCount || this._totalCount)
                    },
                    totalItemsCount: function() {
                        var that = this;
                        return hasGrouping(that) ? that._groupingHelper.totalItemsCount() : that.totalCount()
                    },
                    itemsCount: function() {
                        var that = this;
                        return hasGrouping(that) ? that._groupingHelper.itemsCount() : that.items().length
                    },
                    collapseAll: function(groupIndex) {
                        return this._groupingHelper.collapseAll(groupIndex)
                    },
                    expandAll: function(groupIndex) {
                        return this._groupingHelper.expandAll(groupIndex)
                    },
                    pagesCount: function() {
                        var that = this,
                            count = that.totalItemsCount(),
                            pageSize = that.pageSize();
                        if (pageSize && count > 0)
                            return Math.max(1, Math.ceil(count / pageSize));
                        return 1
                    },
                    reload: function() {
                        var that = this,
                            prop,
                            userData = that._userData,
                            d = $.Deferred();
                        if (that.isLoading()) {
                            var loadingChangedHandler = function() {
                                    that.loadingChanged.remove(loadingChangedHandler);
                                    setTimeout(function() {
                                        that.reload().done(d.resolve).fail(d.reject)
                                    })
                                };
                            that.loadingChanged.add(loadingChangedHandler)
                        }
                        else
                            $.when(that._groupingHelper.refresh(that._createStoreLoadOptions())).always(function() {
                                for (prop in userData)
                                    if (userData.hasOwnProperty(prop))
                                        delete userData[prop];
                                that._isLastPage = !that._paginate;
                                that._currentTotalCount = 0;
                                that._totalCount = -1;
                                that._hasLastPage = that._isLastPage;
                                that._isLoaded = false;
                                that.load().done(d.resolve).fail(d.reject)
                            });
                        return d
                    },
                    hasKnownLastPage: function() {
                        return this._hasLastPage || this._totalCount >= 0
                    },
                    changeGroupExpand: function(path) {
                        var that = this,
                            groupingHelper = that._groupingHelper;
                        if (hasGrouping(that)) {
                            that._changeLoadingCount(1);
                            groupingHelper.changeGroupExpand(path).always(function() {
                                that._changeLoadingCount(-1)
                            }).done(function() {
                                that.load()
                            })
                        }
                        else
                            that.load()
                    },
                    _createLoadQueue: function() {
                        return DX.createQueue(true)
                    },
                    _scheduleChangedCallbacks: function(deferred) {
                        var that = this,
                            pageIndex = that.pageIndex();
                        that._lastLoadDeferred = deferred;
                        deferred.done(function() {
                            var currentTotalCount,
                                itemsLength;
                            if (that.isLastPage())
                                that._hasLastPage = true;
                            if (that._totalCount >= 0) {
                                if (that._pageIndex >= that.pagesCount()) {
                                    that.pageIndex(that.pagesCount() - 1);
                                    that.load()
                                }
                            }
                            else {
                                itemsLength = that.items().length;
                                currentTotalCount = that.pageIndex() * that.pageSize() + itemsLength;
                                that._currentTotalCount = Math.max(that._currentTotalCount, currentTotalCount);
                                if (itemsLength === 0 && that.pageIndex() >= that.pagesCount()) {
                                    that.pageIndex(that.pagesCount() - 1);
                                    that.load()
                                }
                            }
                            if (pageIndex === that.pageIndex() && !that.isLoading())
                                that.changed.fire()
                        })
                    },
                    _loadFromStore: function(storeLoadOptions, pendingDeferred) {
                        var that = this;
                        var loadTaskCore = function() {
                                var i,
                                    groupOptions,
                                    groupLoadOptions,
                                    groupingHelper = that._groupingHelper,
                                    loads = [],
                                    datas = [];
                                if (that._disposed)
                                    return;
                                if (hasGrouping(that)) {
                                    groupOptions = groupingHelper.processLoadOptions(storeLoadOptions);
                                    groupLoadOptions = groupOptions.loads;
                                    for (i = 0; i < groupLoadOptions.length; i++) {
                                        loads.push(that.store().load(groupLoadOptions[i]));
                                        (function(index) {
                                            loads[index].done(function(data) {
                                                datas[index] = data
                                            })
                                        })(i)
                                    }
                                }
                                else
                                    loads.push(that.store().load(storeLoadOptions));
                                $.when.apply($, loads).done(function(data, extra) {
                                    if (that._disposed)
                                        return;
                                    if (hasGrouping(that)) {
                                        extra = undefined;
                                        data = groupingHelper.mergeLoadedData(datas, groupOptions.data)
                                    }
                                    extra = extra || {totalCount: that._totalCount >= 0 ? that._totalCount : undefined};
                                    that._processStoreLoadResult(data, extra, storeLoadOptions, pendingDeferred)
                                }).fail($.proxy(pendingDeferred.reject, pendingDeferred))
                            };
                        if (that._asyncLoadEnabled)
                            window.setTimeout(loadTaskCore, that._loadingTimeout);
                        else
                            loadTaskCore()
                    }
                }
        }())
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.stateStoring.js */
    (function($, DX) {
        var ui = DX.ui,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        dataGrid.StateStoringController = dataGrid.ViewController.inherit(function() {
            var getStorage = function(options) {
                    var storage = options.type === 'sessionStorage' ? sessionStorage : localStorage;
                    if (!storage)
                        throw new Error("State storing can not be provided due to the restrictions of your browser.");
                    return storage
                };
            var getUniqueStorageKey = function(options) {
                    return 'dx_datagrid_' + (utils.isDefined(options.storageKey) ? options.storageKey : 'storage')
                };
            var dateReviver = function(key, value) {
                    var date;
                    if (typeof value === 'string') {
                        date = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                        if (date)
                            return new Date(Date.UTC(+date[1], +date[2] - 1, +date[3], +date[4], +date[5], +date[6]))
                    }
                    return value
                };
            var processLoadState = function(that, state) {
                    var allowedPageSizes = state.allowedPageSizes,
                        searchText = state.searchText,
                        selectedRowKeys = state.selectedRowKeys,
                        columnsController = that.getController('columns'),
                        selectionController = that.getController('selection'),
                        dataController = that.getController('data'),
                        pagerView = that.getView('pagerView');
                    if (columnsController) {
                        columnsController.setUserState(state.columns);
                        columnsController.columnsChanged.add(function() {
                            that.state({columns: columnsController.getUserState()});
                            that.save()
                        })
                    }
                    if (selectedRowKeys)
                        that.option('selectedRowKeys', selectedRowKeys);
                    if (selectionController)
                        selectionController.selectionChanged.add(function(keys) {
                            that.state({selectedRowKeys: keys});
                            that.save()
                        });
                    if (dataController) {
                        if (allowedPageSizes && that.option('pager.allowedPageSizes') === 'auto' && allowedPageSizes)
                            that.option('pager').allowedPageSizes = allowedPageSizes;
                        if (searchText)
                            dataController.searchByText(searchText);
                        dataController.changed.add(function() {
                            that.state({
                                searchText: dataController.getSearchText(),
                                pageIndex: dataController.pageIndex(),
                                pageSize: dataController.pageSize(),
                                allowedPageSizes: pagerView.getPageSizes()
                            });
                            that.save()
                        })
                    }
                };
            return {
                    _loadState: function() {
                        var options = this.option('stateStoring');
                        if (options.type === 'custom')
                            return options.customLoad && options.customLoad();
                        try {
                            return JSON.parse(getStorage(options).getItem(getUniqueStorageKey(options)), dateReviver)
                        }
                        catch(e) {
                            DX.utils.logger.error(e.message)
                        }
                    },
                    _saveState: function(state) {
                        var options = this.option('stateStoring');
                        if (options.type === 'custom') {
                            options.customSave && options.customSave(state);
                            return
                        }
                        try {
                            getStorage(options).setItem(getUniqueStorageKey(options), JSON.stringify(state))
                        }
                        catch(e) {}
                    },
                    publicMethods: function() {
                        return ['state']
                    },
                    isEnabled: function() {
                        var stateStoringOptions = this.option('stateStoring');
                        return stateStoringOptions && stateStoringOptions.enabled
                    },
                    init: function() {
                        var that = this;
                        that._state = {};
                        that._isLoaded = false;
                        that._isLoading = false
                    },
                    isLoaded: function() {
                        return this._isLoaded
                    },
                    isLoading: function() {
                        return this._isLoading
                    },
                    load: function() {
                        var that = this,
                            loadResult;
                        that._isLoading = true;
                        loadResult = that._loadState();
                        if (!loadResult || !$.isFunction(loadResult.done))
                            loadResult = $.Deferred().resolve(loadResult);
                        loadResult.done(function(state) {
                            that._isLoaded = true;
                            that._isLoading = false;
                            that._state = state || {};
                            processLoadState(that, that._state)
                        });
                        return loadResult
                    },
                    state: function(state) {
                        var that = this;
                        if (state === undefined)
                            return that._state;
                        else
                            $.extend(that._state, state)
                    },
                    save: function() {
                        this._saveState(this._state)
                    }
                }
        }());
        dataGrid.registerModule('stateStoring', {
            defaultOptions: function() {
                return {stateStoring: {
                            enabled: false,
                            storageKey: null,
                            type: 'localStorage',
                            customLoad: null,
                            customSave: null
                        }}
            },
            controllers: {stateStoring: ui.dataGrid.StateStoringController},
            extenders: {controllers: {data: {
                        _refreshDataSource: function() {
                            var that = this,
                                callBase = that.callBase,
                                stateStoringController = that.getController('stateStoring');
                            if (stateStoringController.isEnabled() && !stateStoringController.isLoaded())
                                stateStoringController.load().done(function() {
                                    callBase.call(that)
                                });
                            else
                                callBase.call(that)
                        },
                        isLoading: function() {
                            var that = this,
                                stateStoringController = that.getController('stateStoring');
                            return this.callBase() || stateStoringController.isLoading()
                        },
                        _dataSourceOptions: function() {
                            var that = this,
                                result = that.callBase(),
                                stateStoringController = that.getController('stateStoring'),
                                userState;
                            if (stateStoringController.isEnabled()) {
                                userState = stateStoringController.state();
                                if (userState.pageIndex !== undefined)
                                    result.pageIndex = userState.pageIndex;
                                if (userState.pageSize !== undefined)
                                    result.pageSize = userState.pageSize
                            }
                            return result
                        }
                    }}}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.columnsController.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            dataGrid = ui.dataGrid,
            utils = DX.utils,
            dataUtils = DX.data.utils,
            normalizeSortingInfo = dataUtils.normalizeSortingInfo,
            isDefined = utils.isDefined;
        var USER_STATE_FIELD_NAMES = ['initialIndex', 'dataField', 'width', 'visible', 'sortOrder', 'sortIndex', 'groupIndex', 'filterText', 'selectedFilterOperation'];
        var ColumnsController = dataGrid.Controller.inherit(function() {
                var DEFAULT_COLUMN_OPTIONS = {visible: true};
                var DATATYPE_OPERATIONS = {
                        number: ['=', '<>', '<', '>', '<=', '>='],
                        string: ['contains', 'notcontains', 'startswith', 'endswith', '=', '<>'],
                        date: ['=', '<>', '<', '>', '<=', '>=']
                    };
                var FIXED_COLUMN_OPTIONS = {
                        allowResizing: false,
                        allowGrouping: false,
                        allowReordering: false,
                        allowSorting: false,
                        allowHiding: false
                    };
                var GROUP_COLUMN_WIDTH = 30;
                var GROUP_LOCATION = 'group',
                    COLUMN_CHOOSER_LOCATION = 'columnChooser';
                var convertNameToCaption = function(name) {
                        var captionList = [],
                            i,
                            char,
                            isPrevCharNewWord = false,
                            isNewWord = false;
                        for (i = 0; i < name.length; i++) {
                            char = name.charAt(i);
                            isNewWord = char === char.toUpperCase() || char in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
                            if (char === '_' || char === '.') {
                                char = ' ';
                                isNewWord = true
                            }
                            else if (i === 0) {
                                char = char.toUpperCase();
                                isNewWord = true
                            }
                            else if (!isPrevCharNewWord && isNewWord)
                                if (captionList.length > 0)
                                    captionList.push(' ');
                            captionList.push(char);
                            isPrevCharNewWord = isNewWord
                        }
                        return captionList.join('')
                    };
                var createColumn = function(that, columnOptions) {
                        var result,
                            commonColumnOptions,
                            calculatedColumnOptions;
                        if (columnOptions) {
                            if (utils.isString(columnOptions))
                                columnOptions = {dataField: columnOptions};
                            commonColumnOptions = that.getCommonSettings();
                            calculatedColumnOptions = that._createCalculatedColumnOptions(columnOptions);
                            return $.extend(true, {}, DEFAULT_COLUMN_OPTIONS, commonColumnOptions, calculatedColumnOptions, columnOptions)
                        }
                    };
                var createColumnsFromOptions = function(that, columnsOptions) {
                        var result = [];
                        if (columnsOptions)
                            $.each(columnsOptions, function(index, value) {
                                var column = createColumn(that, value);
                                if (column) {
                                    if (column.initialIndex === undefined)
                                        column.initialIndex = index;
                                    result.push(column)
                                }
                            });
                        return result
                    };
                var getValueDataType = function(value) {
                        var dataType = $.type(value);
                        if (dataType === 'string') {
                            if (utils.isNumber(value))
                                dataType = 'number';
                            else if (value.indexOf('</') >= 0 || value.indexOf('/>') >= 0)
                                dataType = 'html'
                        }
                        else if (dataType !== 'boolean' && dataType !== 'number' && dataType !== 'date')
                            dataType = undefined;
                        return dataType
                    };
                var getAlignmentByDataType = function(dataType, isRTL) {
                        switch (dataType) {
                            case'number':
                                return 'right';
                            case'boolean':
                                return 'center';
                            case'date':
                                return 'left';
                            default:
                                return isRTL ? 'right' : 'left'
                        }
                    };
                var getFormatByDataType = function(dataType) {
                        switch (dataType) {
                            case"date":
                                return "shortDate"
                        }
                    };
                var getCustomizeTextByDataType = function(dataType) {
                        if (dataType === 'boolean')
                            return function(e) {
                                    if (e.value)
                                        return this.trueText || 'true';
                                    else
                                        return this.falseText || 'false'
                                }
                    };
                var createColumnsFromDataSource = function(that, dataSource) {
                        var firstItems = getFirstItems(dataSource),
                            fieldName,
                            processedFields = {},
                            i,
                            initialIndex = 0,
                            result = [];
                        for (i = 0; i < firstItems.length; i++)
                            firstItems[i] && $.each(firstItems[i], function(fieldName) {
                                processedFields[fieldName] = true
                            });
                        $.each(processedFields, function(fieldName) {
                            if (fieldName.indexOf('__') !== 0) {
                                var column = createColumn(that, fieldName);
                                column.initialIndex = initialIndex++;
                                result.push(column)
                            }
                        });
                        return result
                    };
                var equalSortParameters = function(sortParameters1, sortParameters2) {
                        var i;
                        if ($.isArray(sortParameters1) && $.isArray(sortParameters2)) {
                            if (sortParameters1.length !== sortParameters2.length)
                                return false;
                            else
                                for (i = 0; i < sortParameters1.length; i++)
                                    if (sortParameters1[i].selector !== sortParameters2[i].selector || sortParameters1[i].desc !== sortParameters2[i].desc || !sortParameters1[i].isExpanded !== !sortParameters2[i].isExpanded)
                                        return false;
                            return true
                        }
                        else
                            return (!sortParameters1 || !sortParameters1.length) === (!sortParameters2 || !sortParameters2.length)
                    };
                var getFirstItems = function(dataSource) {
                        var groupsCount,
                            item,
                            items = [];
                        var getFirstItemsCore = function(items, groupsCount) {
                                var i,
                                    childItems;
                                if (!items || !groupsCount)
                                    return items;
                                for (i = 0; i < items.length; i++) {
                                    childItems = getFirstItemsCore(items[i].items, groupsCount - 1);
                                    if (childItems && childItems.length)
                                        return childItems
                                }
                            };
                        if (dataSource && dataSource.items().length > 0) {
                            groupsCount = normalizeSortingInfo(dataSource.group() || []).length;
                            items = getFirstItemsCore(dataSource.items(), groupsCount) || []
                        }
                        return items
                    };
                var updateColumnIndexes = function(that) {
                        $.each(that._columns, function(index, column) {
                            column.index = index
                        })
                    };
                var updateColumnParameterIndexes = function(that, indexParameterName) {
                        var indexedSortColumns = [],
                            parameterIndex = 0;
                        $.each(that._columns, function(index, column) {
                            var index = column[indexParameterName];
                            if (isDefined(index)) {
                                if (!indexedSortColumns[index])
                                    indexedSortColumns[index] = [];
                                indexedSortColumns[index].push(column);
                                delete column[indexParameterName]
                            }
                        });
                        $.each(indexedSortColumns, function(index, sortColumns) {
                            if (sortColumns)
                                $.each(sortColumns, function() {
                                    this[indexParameterName] = parameterIndex++
                                })
                        });
                        return parameterIndex
                    };
                var updateColumnGroupIndexes = function(that) {
                        var indexPropertyName = 'groupIndex',
                            groupIndex = updateColumnParameterIndexes(that, indexPropertyName);
                        $.each(that._columns, function(index, column) {
                            if (!isDefined(column[indexPropertyName]) && column.grouped)
                                column[indexPropertyName] = groupIndex++;
                            delete column.grouped
                        })
                    };
                var updateColumnSortIndexes = function(that) {
                        var sortIndex = updateColumnParameterIndexes(that, 'sortIndex');
                        $.each(that._columns, function(index, column) {
                            if (!isDefined(column.sortIndex) && !isDefined(column.groupIndex) && (column.sortOrder === 'asc' || column.sortOrder === 'desc'))
                                column.sortIndex = sortIndex++
                        })
                    };
                var parseDate = function(value) {
                        var parsedDate;
                        if (!utils.isDate(value))
                            if (utils.isNumber(value))
                                value = new Date(value);
                            else {
                                parsedDate = Date.parse(value);
                                if (parsedDate)
                                    value = new Date(parsedDate)
                            }
                        return value
                    };
                var applyColumnTypesToDataSource = function(that, dataSource) {
                        var i,
                            columns = that._columns,
                            firstItem = getFirstItems(dataSource)[0],
                            fieldName,
                            userMapFunc,
                            columnTypesMapFunc,
                            columnTypesWithUserMapFunc,
                            groupsCount,
                            dateFieldNames = [],
                            numberFieldNames = [];
                        if (dataSource && dataSource.map) {
                            for (i = 0; i < columns.length; i++) {
                                fieldName = columns[i].dataField;
                                if (fieldName)
                                    switch (columns[i].dataType) {
                                        case"date":
                                            if (!firstItem || !utils.isDate(firstItem[fieldName]))
                                                dateFieldNames.push(fieldName);
                                            break;
                                        case"number":
                                            if (!firstItem || utils.isString(firstItem[fieldName]))
                                                numberFieldNames.push(fieldName);
                                            break
                                    }
                            }
                            var convertValue = function(item, fieldNames, groupsCount, parseFunc) {
                                    if (!groupsCount || !utils.isDefined(item.items))
                                        for (var i = 0; i < fieldNames.length; i++) {
                                            var fieldValue = item[fieldNames[i]];
                                            if (fieldValue)
                                                item[fieldNames[i]] = parseFunc(fieldValue)
                                        }
                                    else
                                        $.each(item.items, function(index, item) {
                                            convertValue(item, fieldNames, groupsCount - 1, parseFunc)
                                        })
                                };
                            if (dateFieldNames.length > 0 || numberFieldNames.length > 0) {
                                userMapFunc = dataSource.map();
                                columnTypesMapFunc = function(item) {
                                    var groupsCount;
                                    if (item) {
                                        groupsCount = normalizeSortingInfo(dataSource.group() || []).length;
                                        convertValue(item, dateFieldNames, groupsCount, parseDate);
                                        convertValue(item, numberFieldNames, groupsCount, Number)
                                    }
                                    return item
                                };
                                columnTypesWithUserMapFunc = function(item) {
                                    item = userMapFunc ? userMapFunc(item) : item;
                                    return columnTypesMapFunc(item)
                                },
                                dataSource.map(columnTypesWithUserMapFunc);
                                if (!dataSource.map()) {
                                    dataSource.store().inserting.remove(that._insertingHandler);
                                    that._insertingHandler = function(values) {
                                        columnTypesWithUserMapFunc(values)
                                    };
                                    dataSource.store().inserting.add(that._insertingHandler)
                                }
                                else
                                    $.each(dataSource.items(), function() {
                                        columnTypesMapFunc(this)
                                    });
                                return dataSource.load()
                            }
                        }
                    };
                var getColumnIndexByVisibleIndex = function(that, visibleIndex, location) {
                        var columns = location === GROUP_LOCATION ? that.getVisibleGroupColumns() : location === COLUMN_CHOOSER_LOCATION ? that.getHiddenColumns() : that.getVisibleColumns(),
                            column = columns[visibleIndex];
                        return column && isDefined(column.index) ? column.index : -1
                    };
                var moveColumnToGroup = function(that, column, groupIndex) {
                        var groupColumns = that.getGroupColumns(),
                            i;
                        if (groupIndex >= 0) {
                            for (i = 0; i < groupColumns.length; i++)
                                if (groupColumns[i].groupIndex >= groupIndex)
                                    groupColumns[i].groupIndex++
                        }
                        else {
                            groupIndex = 0;
                            for (i = 0; i < groupColumns.length; i++)
                                groupIndex = Math.max(groupIndex, groupColumns[i].groupIndex + 1)
                        }
                        column.groupIndex = groupIndex
                    };
                var applyUserState = function(that) {
                        var columnsUserState = that._columnsUserState,
                            columns = that._columns,
                            resultColumns = [],
                            columnsByInitialIndex = [],
                            column,
                            i;
                        if (columnsUserState) {
                            if (columns.length !== columnsUserState.length)
                                return;
                            for (i = 0; i < columns.length; i++)
                                columnsByInitialIndex[columns[i].initialIndex] = columns[i];
                            for (i = 0; i < columnsUserState.length; i++) {
                                column = columnsByInitialIndex[columnsUserState[i].initialIndex];
                                if (column && columnsUserState[i].dataField === column.dataField) {
                                    column = $.extend({}, column);
                                    $.each(USER_STATE_FIELD_NAMES, function(index, value) {
                                        column[value] = columnsUserState[i][value]
                                    });
                                    resultColumns.push(column)
                                }
                                else
                                    return
                            }
                            that._columns = resultColumns
                        }
                    };
                var updateIndexes = function(that) {
                        updateColumnIndexes(that);
                        updateColumnGroupIndexes(that);
                        updateColumnSortIndexes(that)
                    };
                return {
                        init: function() {
                            var that = this,
                                columns = that.option('columns');
                            that._columns = columns ? createColumnsFromOptions(that, columns) : [];
                            that._isColumnsFromOptions = !!columns;
                            if (that._isColumnsFromOptions)
                                applyUserState(that);
                            else
                                that._columns = that._columnsUserState || that._columns;
                            if (that._dataSourceApplied)
                                that.applyDataSource(that._dataSource, true);
                            else
                                updateIndexes(that)
                        },
                        callbackNames: function() {
                            return ['columnsChanged']
                        },
                        optionChanged: function(name, value, prevValue) {
                            switch (name) {
                                case'columns':
                                case'commonColumnSettings':
                                case'columnAutoWidth':
                                case'allowColumnResizing':
                                case'allowColumnReordering':
                                case'grouping':
                                case'groupPanel':
                                case'regenerateColumnsByVisibleItems':
                                case'customizeColumns':
                                case'editing':
                                case'rtlEnabled':
                                    this.init();
                                    break
                            }
                        },
                        publicMethods: function() {
                            return ['addColumn', 'columnOption', 'columnCount']
                        },
                        applyDataSource: function(dataSource, forceApplying) {
                            var that = this,
                                isDataSourceLoaded = dataSource && dataSource.isLoaded(),
                                applyingComplete;
                            that._dataSource = dataSource;
                            if (!that._dataSourceApplied || that._dataSourceColumnsCount === 0 || forceApplying || that.option('regenerateColumnsByVisibleItems'))
                                if (isDataSourceLoaded) {
                                    if (!that._isColumnsFromOptions) {
                                        that._columns = createColumnsFromDataSource(that, dataSource);
                                        that._dataSourceColumnsCount = that._columns.length;
                                        applyUserState(that)
                                    }
                                    that.updateColumns(dataSource);
                                    $.when(applyColumnTypesToDataSource(that, dataSource)).always(function() {
                                        that._dataSourceApplied = true
                                    })
                                }
                        },
                        reset: function() {
                            this._dataSourceApplied = false;
                            this._dataSourceColumnsCount = undefined
                        },
                        isInitialized: function() {
                            return !!this._columns.length
                        },
                        isDataSourceApplied: function() {
                            return this._dataSourceApplied
                        },
                        getCommonSettings: function() {
                            var commonColumnSettings = this.option('commonColumnSettings') || {},
                                groupingOptions = this.option('grouping') || {},
                                groupPanelOptions = this.option('groupPanel') || {};
                            return $.extend({
                                    allowResizing: this.option('allowColumnResizing'),
                                    allowReordering: this.option('allowColumnReordering'),
                                    autoExpandGroup: groupingOptions.autoExpandAll,
                                    allowCollapsing: groupingOptions.allowCollapsing,
                                    allowGrouping: groupPanelOptions.allowColumnDragging && groupPanelOptions.visible
                                }, commonColumnSettings)
                        },
                        isColumnOptionUsed: function(optionName) {
                            for (var i = 0; i < this._columns.length; i++)
                                if (this._columns[i][optionName])
                                    return true
                        },
                        getColumns: function() {
                            return $.extend(true, [], this._columns)
                        },
                        getGroupColumns: function() {
                            var result = [];
                            $.each(this._columns, function() {
                                var column = this;
                                if (isDefined(column.groupIndex))
                                    result[column.groupIndex] = column
                            });
                            return result
                        },
                        getVisibleGroupColumns: function() {
                            return $.map(this.getGroupColumns(), function(column) {
                                    if (column && column.visible)
                                        return column
                                })
                        },
                        getVisibleColumns: function() {
                            var visibleColumns = $.map(this.getVisibleGroupColumns(), function(column) {
                                    return $.extend({}, column, {width: GROUP_COLUMN_WIDTH}, FIXED_COLUMN_OPTIONS)
                                });
                            var notGroupedColumnsCount = 0;
                            $.each(this._columns, function() {
                                var column = this;
                                if (column.visible && !isDefined(column.groupIndex)) {
                                    column = $.extend(true, {}, column);
                                    visibleColumns.push(column);
                                    notGroupedColumnsCount++
                                }
                            });
                            if (!notGroupedColumnsCount && this._columns.length)
                                visibleColumns.push({command: 'empty'});
                            return visibleColumns
                        },
                        getHiddenColumns: function() {
                            var result = [];
                            $.each(this._columns, function(_, column) {
                                if (!column.visible)
                                    result.push(column)
                            });
                            return result
                        },
                        allowMoveColumn: function(fromVisibleIndex, toVisibleIndex, sourceLocation, targetLocation) {
                            var that = this,
                                columnIndex = getColumnIndexByVisibleIndex(that, fromVisibleIndex, sourceLocation),
                                sourceColumn = that._columns[columnIndex];
                            if (sourceColumn && (sourceColumn.allowReordering || sourceColumn.allowGrouping || sourceColumn.allowHiding)) {
                                if (sourceLocation === targetLocation) {
                                    if (sourceLocation === COLUMN_CHOOSER_LOCATION)
                                        return false;
                                    return fromVisibleIndex !== toVisibleIndex && fromVisibleIndex + 1 !== toVisibleIndex
                                }
                                else if (sourceLocation === GROUP_LOCATION && targetLocation !== COLUMN_CHOOSER_LOCATION || targetLocation === GROUP_LOCATION)
                                    return sourceColumn && sourceColumn.allowGrouping;
                                else if (sourceLocation === COLUMN_CHOOSER_LOCATION || targetLocation === COLUMN_CHOOSER_LOCATION)
                                    return sourceColumn && sourceColumn.allowHiding;
                                return true
                            }
                            return false
                        },
                        moveColumn: function(fromVisibleIndex, toVisibleIndex, sourceLocation, targetLocation) {
                            var that = this,
                                fromIndex,
                                toIndex,
                                targetGroupIndex,
                                isGroupMoving = sourceLocation === GROUP_LOCATION || targetLocation === GROUP_LOCATION,
                                column;
                            fromIndex = getColumnIndexByVisibleIndex(that, fromVisibleIndex, sourceLocation);
                            toIndex = getColumnIndexByVisibleIndex(that, toVisibleIndex, targetLocation);
                            if (fromIndex >= 0) {
                                column = that._columns[fromIndex];
                                targetGroupIndex = toIndex >= 0 ? that._columns[toIndex].groupIndex : -1;
                                if (isDefined(column.groupIndex)) {
                                    if (targetGroupIndex > column.groupIndex)
                                        targetGroupIndex--;
                                    delete column.groupIndex;
                                    delete column.sortOrder;
                                    updateColumnGroupIndexes(that)
                                }
                                if (targetLocation === GROUP_LOCATION)
                                    moveColumnToGroup(that, column, targetGroupIndex);
                                else if (toVisibleIndex >= 0) {
                                    that._columns.splice(fromIndex, 1);
                                    if (toIndex < 0)
                                        that._columns.push(column);
                                    else {
                                        var spliceIndex = toIndex > fromIndex ? toIndex - 1 : toIndex;
                                        that._columns.splice(spliceIndex, 0, column)
                                    }
                                    updateColumnIndexes(that)
                                }
                                column.visible = targetLocation === COLUMN_CHOOSER_LOCATION ? false : true;
                                that.columnsChanged.fire({changeType: isGroupMoving ? 'grouping' : 'columns'})
                            }
                        },
                        changeSortOrder: function(columnIndex, sortOrder) {
                            var that = this,
                                commonColumnSettings = that.getCommonSettings(),
                                sortingOptions = that.option('sorting'),
                                sortingMode = sortingOptions && sortingOptions.mode,
                                needResetSorting = sortingMode === 'single' || !sortOrder,
                                allowSorting = sortingMode === 'single' || sortingMode === 'multiple',
                                column = that._columns[columnIndex],
                                nextSortOrder = function(column) {
                                    if (sortOrder === "ctrl") {
                                        delete column.sortOrder;
                                        delete column.sortIndex
                                    }
                                    else if (isDefined(column.groupIndex) || isDefined(column.sortIndex))
                                        column.sortOrder = column.sortOrder === 'desc' ? 'asc' : 'desc';
                                    else
                                        column.sortOrder = 'asc'
                                },
                                isSortingChanged = false;
                            if (allowSorting && column && column.allowSorting) {
                                if (needResetSorting && !isDefined(column.groupIndex))
                                    $.each(that._columns, function(index) {
                                        if (index !== columnIndex && this.sortOrder && !isDefined(this.groupIndex)) {
                                            delete this.sortOrder;
                                            delete this.sortIndex;
                                            isSortingChanged = true
                                        }
                                    });
                                if (sortOrder === 'asc' || sortOrder === 'desc') {
                                    if (column.sortOrder !== sortOrder) {
                                        column.sortOrder = sortOrder;
                                        isSortingChanged = true
                                    }
                                }
                                else if (sortOrder === 'none') {
                                    if (column.sortOrder) {
                                        delete column.sortIndex;
                                        delete column.sortOrder;
                                        isSortingChanged = true
                                    }
                                }
                                else {
                                    nextSortOrder(column);
                                    isSortingChanged = true
                                }
                            }
                            if (isSortingChanged) {
                                updateColumnSortIndexes(that);
                                that.columnsChanged.fire({changeType: 'sorting'})
                            }
                        },
                        getSortDataSourceParameters: function() {
                            var that = this,
                                sortColumns = [],
                                sort = [];
                            $.each(that._columns, function() {
                                if (this.dataField && this.visible && isDefined(this.sortIndex) && !isDefined(this.groupIndex))
                                    sortColumns[this.sortIndex] = this
                            });
                            $.each(sortColumns, function() {
                                var sortOrder = this && this.sortOrder;
                                if (sortOrder === 'asc' || sortOrder === 'desc')
                                    sort.push({
                                        selector: this.dataField,
                                        desc: this.sortOrder === 'desc'
                                    })
                            });
                            return sort.length > 0 ? sort : null
                        },
                        getGroupDataSourceParameters: function() {
                            var group = [];
                            $.each(this.getVisibleGroupColumns(), function() {
                                if (this.dataField)
                                    group.push({
                                        selector: this.dataField,
                                        desc: this.sortOrder === 'desc',
                                        isExpanded: !!this.autoExpandGroup
                                    })
                            });
                            return group.length > 0 ? group : null
                        },
                        refresh: function(updateNewLookupsOnly) {
                            var deferreds = [];
                            $.each(this._columns, function() {
                                var lookup = this.lookup;
                                if (lookup) {
                                    if (updateNewLookupsOnly && lookup.valueMap)
                                        return;
                                    if (lookup.update)
                                        deferreds.push(lookup.update())
                                }
                            });
                            return $.when.apply($, deferreds)
                        },
                        _updateColumnDataTypes: function(dataSource) {
                            var firstItems = getFirstItems(dataSource),
                                rtlEnabled = this.option("rtlEnabled");
                            $.each(this._columns, function(index, column) {
                                var i,
                                    value,
                                    dataType,
                                    lookup = column.lookup;
                                if (column.dataField && firstItems.length)
                                    for (i = 0; (!column.dataType || lookup && !lookup.dataType) && i < firstItems.length; i++) {
                                        value = column.calculateCellValue(firstItems[i]);
                                        column.dataType = getValueDataType(value);
                                        if (lookup)
                                            lookup.dataType = getValueDataType(lookup.calculateCellValue(value))
                                    }
                                dataType = lookup ? lookup.dataType : column.dataType;
                                if (dataType) {
                                    column.alignment = column.alignment || getAlignmentByDataType(dataType, rtlEnabled);
                                    column.format = column.format || getFormatByDataType(dataType);
                                    column.customizeText = column.customizeText || getCustomizeTextByDataType(dataType);
                                    if (!isDefined(column.filterOperations))
                                        column.filterOperations = !lookup && DATATYPE_OPERATIONS[dataType] || []
                                }
                            })
                        },
                        updateColumns: function(dataSource) {
                            var that = this,
                                customizeColumns = that.option('customizeColumns'),
                                sortParameters,
                                groupParameters;
                            that.updateSortingGrouping(dataSource);
                            if (!dataSource || dataSource.isLoaded()) {
                                sortParameters = dataSource ? dataSource.sort() || [] : that.getSortDataSourceParameters();
                                groupParameters = dataSource ? dataSource.group() || [] : that.getGroupDataSourceParameters();
                                if (customizeColumns) {
                                    customizeColumns(that._columns);
                                    that._columns = createColumnsFromOptions(that, that._columns)
                                }
                                updateIndexes(that);
                                that._updateColumnDataTypes(dataSource);
                                $.when(that.refresh(true)).always(function() {
                                    that._updateColumnDataTypes(dataSource);
                                    if (!equalSortParameters(sortParameters, that.getSortDataSourceParameters()))
                                        that.columnsChanged.fire({changeType: 'sorting'});
                                    else if (!equalSortParameters(groupParameters, that.getGroupDataSourceParameters()))
                                        that.columnsChanged.fire({changeType: 'grouping'});
                                    else
                                        that.columnsChanged.fire({changeType: 'columns'})
                                })
                            }
                        },
                        updateSortingGrouping: function(dataSource) {
                            var that = this,
                                sortParameters,
                                groupParameters,
                                columnsGroupParameters,
                                columnsSortParameters,
                                updateSortGroupParameterIndexes = function(columns, sortParameters, indexParameterName) {
                                    var i;
                                    $.each(columns, function(index, column) {
                                        if (column.dataField) {
                                            delete column[indexParameterName];
                                            if (sortParameters && sortParameters.length)
                                                for (i = 0; i < sortParameters.length; i++)
                                                    if (sortParameters[i].selector === column.dataField) {
                                                        column.sortOrder = column.sortOrder || (sortParameters[i].desc ? 'desc' : 'asc');
                                                        column[indexParameterName] = i;
                                                        break
                                                    }
                                        }
                                    })
                                };
                            if (dataSource) {
                                sortParameters = normalizeSortingInfo(dataSource.sort() || []);
                                groupParameters = normalizeSortingInfo(dataSource.group() || []);
                                columnsGroupParameters = that.getGroupDataSourceParameters();
                                columnsSortParameters = that.getSortDataSourceParameters();
                                if (!that._columns.length) {
                                    $.each(groupParameters, function(index, group) {
                                        that._columns.push(group.selector)
                                    });
                                    $.each(sortParameters, function(index, sort) {
                                        that._columns.push(sort.selector)
                                    });
                                    that._columns = createColumnsFromOptions(that, that._columns)
                                }
                                if (!columnsGroupParameters && !equalSortParameters(groupParameters, columnsGroupParameters)) {
                                    that.__groupingUpdated = true;
                                    updateSortGroupParameterIndexes(that._columns, groupParameters, 'groupIndex')
                                }
                                if (!columnsSortParameters && !equalSortParameters(sortParameters, columnsSortParameters)) {
                                    that.__sortingUpdated = true;
                                    updateSortGroupParameterIndexes(that._columns, sortParameters, 'sortIndex')
                                }
                            }
                        },
                        columnCount: function() {
                            return this._columns.length
                        },
                        columnOption: function(identificator, optionName, value) {
                            var that = this,
                                i,
                                changeType,
                                columns = that._columns,
                                column;
                            for (i = 0; i < columns.length; i++)
                                if (columns[i].initialIndex === identificator || columns[i].dataField === identificator || columns[i].caption === identificator) {
                                    column = columns[i];
                                    break
                                }
                            if (column) {
                                if (arguments.length === 1)
                                    return $.extend({}, column);
                                if (utils.isString(optionName)) {
                                    var optionGetter = dataUtils.compileGetter(optionName);
                                    if (arguments.length === 2)
                                        return optionGetter(column, {functionsAsIs: true});
                                    if (optionGetter(column, {functionsAsIs: true}) !== value) {
                                        if (optionName === 'groupIndex') {
                                            moveColumnToGroup(that, column, value);
                                            changeType = 'grouping'
                                        }
                                        else if (optionName === 'sortIndex' || optionName === 'sortOrder')
                                            changeType = 'sorting';
                                        else
                                            changeType = 'columns';
                                        dataUtils.compileSetter(optionName)(column, value, {functionsAsIs: true})
                                    }
                                }
                                else if (utils.isObject(optionName)) {
                                    if (optionName.groupIndex !== undefined) {
                                        moveColumnToGroup(that, column, optionName.groupIndex);
                                        changeType = 'grouping'
                                    }
                                    else if (optionName.sortIndex !== undefined || optionName.sortOrder !== undefined)
                                        changeType = 'sorting';
                                    else
                                        changeType = 'columns';
                                    $.extend(true, column, optionName)
                                }
                                updateIndexes(that);
                                if (changeType)
                                    that.columnsChanged.fire({
                                        changeType: changeType,
                                        columnIndex: column.initialIndex,
                                        optionName: optionName,
                                        column: $.extend({}, column)
                                    })
                            }
                        },
                        getVisibleIndex: function(index) {
                            var i,
                                visibleColumns = this.getVisibleColumns();
                            for (i = 0; i < visibleColumns.length; i++)
                                if (visibleColumns[i].index === index)
                                    return i;
                            return -1
                        },
                        addColumn: function(options) {
                            var that = this;
                            that._columns.push(createColumn(that, options));
                            that.updateColumns()
                        },
                        getUserState: function() {
                            var columns = this._columns,
                                result = [],
                                i;
                            for (i = 0; i < columns.length; i++) {
                                result[i] = {};
                                $.each(USER_STATE_FIELD_NAMES, function(index, value) {
                                    if (columns[i][value] !== undefined)
                                        result[i][value] = columns[i][value]
                                })
                            }
                            return result
                        },
                        setUserState: function(state) {
                            this._columnsUserState = state;
                            this.init()
                        },
                        _createCalculatedColumnOptions: function(columnOptions) {
                            var calculatedColumnOptions = {};
                            if (columnOptions.dataField) {
                                calculatedColumnOptions = {
                                    caption: convertNameToCaption(columnOptions.dataField),
                                    calculateCellValue: dataUtils.compileGetter(columnOptions.dataField),
                                    validate: function(value) {
                                        if (typeof value === 'string')
                                            return !value || !this.parseValue || !!this.parseValue(value);
                                        return true
                                    },
                                    parseValue: function(text) {
                                        var column = this,
                                            result,
                                            parsedDate;
                                        if (column.dataType === 'number') {
                                            if (utils.isNumber(text))
                                                result = Number(text)
                                        }
                                        else if (column.dataType === 'boolean') {
                                            if (text === 'true')
                                                result = true;
                                            else if (text === 'false')
                                                result = false
                                        }
                                        else if (column.dataType === 'date') {
                                            parsedDate = Globalize.parseDate(text);
                                            if (parsedDate)
                                                result = parsedDate
                                        }
                                        else
                                            result = text;
                                        return result
                                    }
                                };
                                if (columnOptions.lookup)
                                    calculatedColumnOptions.lookup = {
                                        calculateCellValue: function(value) {
                                            return this.valueMap && this.valueMap[value]
                                        },
                                        updateValueMap: function() {
                                            var calculateValue,
                                                calculateDisplayValue,
                                                item,
                                                i;
                                            this.valueMap = {};
                                            if (this.items) {
                                                calculateValue = dataUtils.compileGetter(this.valueExpr);
                                                calculateDisplayValue = dataUtils.compileGetter(this.displayExpr);
                                                for (i = 0; i < this.items.length; i++) {
                                                    item = this.items[i];
                                                    this.valueMap[calculateValue(item)] = calculateDisplayValue(item)
                                                }
                                            }
                                        },
                                        update: function() {
                                            var that = this,
                                                dataSource = that.dataSource;
                                            if (dataSource)
                                                if (utils.isObject(dataSource) || utils.isArray(dataSource)) {
                                                    dataSource = new DX.data.DataSource($.extend(true, {paginate: false}, dataUtils.normalizeDataSourceOptions(dataSource)));
                                                    return dataSource.load().done(function(data) {
                                                            that.items = data;
                                                            that.updateValueMap && that.updateValueMap()
                                                        })
                                                }
                                                else
                                                    DX.utils.logger.error("Unexpected type of data source is provided for a lookup column. For the list of supported types, see http://js.devexpress.com/Documentation/ApiReference/UI_Widgets/dxDataGrid/Configuration/columns/lookup#dataSource");
                                            else
                                                that.updateValueMap && that.updateValueMap()
                                        }
                                    }
                            }
                            else
                                $.extend(true, calculatedColumnOptions, {
                                    allowSorting: false,
                                    calculateCellValue: function() {
                                        return null
                                    }
                                });
                            calculatedColumnOptions.resizedCallbacks = $.Callbacks();
                            if (columnOptions.resized)
                                calculatedColumnOptions.resizedCallbacks.add($.proxy(columnOptions.resized, columnOptions));
                            return calculatedColumnOptions
                        }
                    }
            }());
        ui.dataGrid.ColumnsController = ColumnsController;
        dataGrid.registerModule('columns', {
            defaultOptions: function() {
                return {
                        commonColumnSettings: {
                            allowFiltering: true,
                            allowHiding: true,
                            allowSorting: true,
                            allowEditing: true,
                            trueText: Globalize.localize("dxDataGrid-trueText"),
                            falseText: Globalize.localize("dxDataGrid-falseText")
                        },
                        grouping: {
                            autoExpandAll: true,
                            allowCollapsing: true,
                            groupContinuesMessage: Globalize.localize("dxDataGrid-groupContinuesMessage"),
                            groupContinuedMessage: Globalize.localize("dxDataGrid-groupContinuedMessage")
                        },
                        allowColumnReordering: false,
                        allowColumnResizing: false,
                        columns: undefined,
                        regenerateColumnsByVisibleItems: false,
                        sorting: {
                            mode: 'single',
                            ascendingText: Globalize.localize("dxDataGrid-sortingAscendingText"),
                            descendingText: Globalize.localize("dxDataGrid-sortingDescendingText"),
                            clearText: Globalize.localize("dxDataGrid-sortingClearText")
                        },
                        customizeColumns: null
                    }
            },
            controllers: {columns: ColumnsController}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.selection.js */
    (function($, DX) {
        var dataGrid = DX.ui.dataGrid,
            events = DX.ui.events,
            utils = DX.utils;
        var DATAGRID_EDITOR_CELL_CLASS = "dx-editor-cell",
            DATAGRID_ROW_SELECTION_CLASS = "dx-selection",
            DATAGRID_SELECT_CHECKBOX_CLASS = "dx-select-checkbox",
            DATAGRID_CHECKBOX_SIZE_CLASS = "dx-datagrid-checkbox-size",
            LONG_TAP_TIME = 500,
            MAX_EQUAL_KEYS_LEVEL = 3;
        $.extend(dataGrid.__internals, {DATAGRID_ROW_SELECTION_CLASS: DATAGRID_ROW_SELECTION_CLASS});
        var SHOW_CHECKBOXES_MODE = 'selection.showCheckBoxesInMultipleMode';
        dataGrid.SelectionController = dataGrid.Controller.inherit(function() {
            var SELECTION_MODE = 'selection.mode';
            var isSelectable = function(selectionMode) {
                    return selectionMode === 'single' || selectionMode === 'multiple'
                };
            var indexOfSelectedItemKey = function(that, key, isSelectAll) {
                    var index,
                        selectedItemKeys = isSelectAll ? that._unselectedItemKeys : that._selectedItemKeys;
                    if (utils.isObject(key)) {
                        for (index = 0; index < selectedItemKeys.length; index++)
                            if (equalKeys(selectedItemKeys[index], key))
                                return index;
                        return -1
                    }
                    else
                        return $.inArray(key, selectedItemKeys)
                };
            var addSelectedItem = function(that, itemData) {
                    var key = that.getController('data').keyOf(itemData),
                        keyIndex;
                    if (indexOfSelectedItemKey(that, key) === -1) {
                        that._selectedItemKeys.push(key);
                        that._addedItemKeys.push(key);
                        that._selectedItems.push(itemData)
                    }
                    if (that._isSelectAll) {
                        keyIndex = indexOfSelectedItemKey(that, key, true);
                        that._unselectedItemKeys.splice(keyIndex, 1)
                    }
                };
            var removeSelectedItem = function(that, key) {
                    var keyIndex = indexOfSelectedItemKey(that, key);
                    if (keyIndex >= 0) {
                        that._selectedItemKeys.splice(keyIndex, 1);
                        that._removedItemKeys.push(key);
                        that._selectedItems.splice(keyIndex, 1);
                        if (that._isSelectAll && indexOfSelectedItemKey(that, key, true) === -1)
                            that._unselectedItemKeys.push(key)
                    }
                };
            var clearSelectedItems = function(that) {
                    setSelectedItems(that, [], [])
                };
            var setSelectedItems = function(that, keys, items, isSelectAll) {
                    var i,
                        oldSelectedItemKeys = that._selectedItemKeys;
                    that._selectedItemKeys = keys;
                    that._selectedItems = items;
                    that._unselectedItemKeys = [];
                    that._isSelectAll = !!isSelectAll;
                    for (i = 0; i < oldSelectedItemKeys.length; i++)
                        if ($.inArray(oldSelectedItemKeys[i], keys) === -1)
                            that._removedItemKeys.push(oldSelectedItemKeys[i]);
                    for (i = 0; i < keys.length; i++)
                        if ($.inArray(keys[i], oldSelectedItemKeys) === -1)
                            that._addedItemKeys.push(keys[i])
                };
            var equalKeys = function(key1, key2, level) {
                    var propertyName,
                        i;
                    level = level || 0;
                    if (level < MAX_EQUAL_KEYS_LEVEL)
                        if (utils.isObject(key1) && utils.isObject(key2)) {
                            for (propertyName in key1)
                                if (key1.hasOwnProperty(propertyName) && !equalKeys(key1[propertyName], key2[propertyName], level + 1))
                                    return false;
                            for (propertyName in key2)
                                if (!(propertyName in key1))
                                    return false;
                            return true
                        }
                        else if (utils.isArray(key1) && utils.isArray(key2)) {
                            if (key1.length !== key2.length)
                                return false;
                            for (i = 0; i < key1.length; i++)
                                if (!equalKeys(key1[i], key2[i], level + 1))
                                    return false;
                            return true
                        }
                        else if (utils.isDate(key1) && utils.isDate(key2))
                            return key1.getTime() === key2.getTime();
                        else
                            return key1 === key2;
                    return true
                };
            var resetItemSelectionWhenShiftKeyPressed = function(that) {
                    delete that._shiftFocusedItemIndex
                };
            var isDataItem = function(row) {
                    return row && row.rowType === "data"
                };
            var changeItemSelectionWhenShiftKeyPressed = function(that, itemIndex, items) {
                    var isSelectedItemsChanged = false,
                        itemIndexStep,
                        index,
                        dataController = that.getController('data'),
                        isFocusedItemSelected = items[that._focusedItemIndex] && that.isSelectedItem(dataController.keyOf(items[that._focusedItemIndex].data));
                    var addRemoveSelectedItem = function(that, data, isRemove) {
                            if (isRemove)
                                removeSelectedItem(that, dataController.keyOf(data));
                            else
                                addSelectedItem(that, data)
                        };
                    if (!utils.isDefined(that._shiftFocusedItemIndex))
                        that._shiftFocusedItemIndex = that._focusedItemIndex;
                    if (that._shiftFocusedItemIndex !== that._focusedItemIndex) {
                        itemIndexStep = that._focusedItemIndex < that._shiftFocusedItemIndex ? 1 : -1;
                        for (index = that._focusedItemIndex; index !== that._shiftFocusedItemIndex; index += itemIndexStep)
                            if (isDataItem(items[index])) {
                                addRemoveSelectedItem(that, items[index].data, true);
                                isSelectedItemsChanged = true
                            }
                    }
                    if (itemIndex !== that._shiftFocusedItemIndex) {
                        itemIndexStep = itemIndex < that._shiftFocusedItemIndex ? 1 : -1;
                        for (index = itemIndex; index !== that._shiftFocusedItemIndex; index += itemIndexStep)
                            if (isDataItem(items[index])) {
                                addRemoveSelectedItem(that, items[index].data, false);
                                isSelectedItemsChanged = true
                            }
                    }
                    if (isDataItem(items[that._focusedItemIndex]) && !isFocusedItemSelected) {
                        addRemoveSelectedItem(that, items[that._focusedItemIndex].data, false);
                        isSelectedItemsChanged = true
                    }
                    return isSelectedItemsChanged
                };
            var createSelectedItemsFilterCriteria = function(dataSource, selectedItemKeys, isSelectAll) {
                    var keyCriteria,
                        i,
                        key = dataSource && dataSource.key(),
                        criteria = [];
                    if (dataSource)
                        if (key)
                            $.each(selectedItemKeys, function(index, keyValue) {
                                if (criteria.length > 0)
                                    criteria.push(isSelectAll ? 'and' : 'or');
                                if ($.isArray(key)) {
                                    keyCriteria = [];
                                    for (i = 0; i < key.length; i++) {
                                        if (i > 0)
                                            keyCriteria.push(isSelectAll ? 'or' : 'and');
                                        keyCriteria.push([key[i], isSelectAll ? '<>' : '=', keyValue[key[i]]])
                                    }
                                    criteria.push(keyCriteria)
                                }
                                else
                                    criteria.push([key, isSelectAll ? '<>' : '=', keyValue])
                            });
                        else
                            criteria = function(item) {
                                var i;
                                for (i = 0; i < selectedItemKeys.length; i++)
                                    if (equalKeys(selectedItemKeys[i], item))
                                        return !isSelectAll;
                                return isSelectAll
                            };
                    if (criteria.length > 0 || $.isFunction(criteria))
                        return criteria
                };
            var updateSelectedItems = function(that) {
                    var changedItemIndexes = [],
                        dataController = that.getController('data'),
                        addedItemKeys,
                        removedItemKeys;
                    if (dataController) {
                        $.each(dataController.items(), function(index, row) {
                            var key = dataController.keyOf(row.data),
                                i;
                            if (isDataItem(row) && row.isSelected !== that.isSelectedItem(key))
                                changedItemIndexes.push(index)
                        });
                        if (changedItemIndexes.length > 0) {
                            if (that.option(SHOW_CHECKBOXES_MODE) === 'onClick')
                                if (that._selectedItemKeys.length > 1)
                                    that.startSelectionWithCheckboxes();
                                else if (that._selectedItemKeys.length === 0)
                                    that.stopSelectionWithCheckboxes();
                            dataController.updateItems({
                                changeType: 'updateSelection',
                                itemIndexes: changedItemIndexes
                            })
                        }
                        addedItemKeys = that._addedItemKeys;
                        removedItemKeys = that._removedItemKeys;
                        if (addedItemKeys.length || removedItemKeys.length) {
                            that._selectedItemsInternalChange = true;
                            that.option("selectedRowKeys", that._selectedItemKeys.slice(0));
                            that._selectedItemsInternalChange = false;
                            that.selectionChanged.fire(that._selectedItemKeys);
                            that.executeAction("selectionChanged", {
                                selectedRowsData: that._selectedItems,
                                selectedRowKeys: that._selectedItemKeys,
                                currentSelectedRowKeys: addedItemKeys,
                                currentDeselectedRowKeys: removedItemKeys
                            })
                        }
                        that._addedItemKeys = [];
                        that._removedItemKeys = []
                    }
                };
            return {
                    init: function() {
                        var that = this;
                        that._isSelectionWithCheckboxes = false;
                        that._focusedItemIndex = -1;
                        that._selectedItemKeys = [];
                        that._unselectedItemKeys = [];
                        that._selectedItems = [];
                        that._addedItemKeys = [];
                        that._removedItemKeys = [];
                        that._isSelectAll = false;
                        that.createAction("selectionChanged")
                    },
                    callbackNames: function() {
                        return ['selectionChanged']
                    },
                    optionChanged: function(name, value, prevValue) {
                        switch (name) {
                            case"selection":
                                this.init();
                                this.getController('columns').updateColumns();
                                break;
                            case"selectedRowKeys":
                                if (utils.isArray(value) && !this._selectedItemsInternalChange)
                                    this.selectRows(value);
                                break;
                            case"selectionChanged":
                                this.createAction("selectionChanged");
                                break
                        }
                    },
                    publicMethods: function() {
                        return ['selectRows', 'selectRowsByIndexes', 'getSelectedRowKeys', 'getSelectedRowsData', 'clearSelection', 'selectAll', 'startSelectionWithCheckboxes', 'stopSelectionWithCheckboxes']
                    },
                    isSelectedItem: function(key) {
                        var index = indexOfSelectedItemKey(this, key);
                        return index !== -1
                    },
                    isSelectColumnVisible: function() {
                        var showCheckboxesMode = this.option(SHOW_CHECKBOXES_MODE);
                        return this.option(SELECTION_MODE) === 'multiple' && (showCheckboxesMode === 'always' || showCheckboxesMode === 'onClick' || this._isSelectionWithCheckboxes)
                    },
                    isSelectAll: function() {
                        return this._isSelectAll && !this._unselectedItemKeys.length
                    },
                    selectAll: function() {
                        if (this.option(SHOW_CHECKBOXES_MODE) === 'onClick')
                            this.startSelectionWithCheckboxes();
                        return this.selectedItemKeys([], true)
                    },
                    clearSelection: function() {
                        this.selectedItemKeys([])
                    },
                    refresh: function() {
                        var that = this,
                            result;
                        if (that.isSelectAll())
                            result = that.selectAll();
                        else
                            result = that.selectedItemKeys(that.option("selectedRowKeys") || []);
                        return result.done(function(selectedRows) {
                                updateSelectedItems(that)
                            })
                    },
                    selectedItemKeys: function(value, isSelectAll) {
                        var that = this,
                            keys,
                            criteria,
                            isFunctionCriteria,
                            deferred,
                            dataSource = that.getController('data').dataSource(),
                            store = dataSource && dataSource.store(),
                            dataSourceFilter,
                            filter;
                        if (utils.isDefined(value)) {
                            if (store) {
                                keys = $.isArray(value) ? $.extend(true, [], value) : [value];
                                that._isSelectAll = isSelectAll;
                                criteria = createSelectedItemsFilterCriteria(dataSource, keys, isSelectAll);
                                isFunctionCriteria = $.isFunction(criteria);
                                if (criteria || isSelectAll) {
                                    dataSourceFilter = dataSource.filter();
                                    if (criteria && !isFunctionCriteria && dataSourceFilter) {
                                        filter = [];
                                        filter.push(criteria);
                                        filter.push(dataSourceFilter)
                                    }
                                    else if (dataSourceFilter)
                                        filter = dataSourceFilter;
                                    else if (criteria && !isFunctionCriteria)
                                        filter = criteria;
                                    deferred = $.Deferred();
                                    store.load({filter: filter}).done(function(items) {
                                        if (isFunctionCriteria)
                                            new DX.data.ArrayStore(items).load({filter: criteria}).done(function(items) {
                                                deferred.resolve(items)
                                            });
                                        else
                                            deferred.resolve(items)
                                    })
                                }
                            }
                            deferred = deferred || $.Deferred().resolve([]);
                            deferred.done(function(items) {
                                var i,
                                    key,
                                    keys = [];
                                if (store && items.length > 0)
                                    for (i = 0; i < items.length; i++) {
                                        key = store.keyOf(items[i]);
                                        keys.push(key)
                                    }
                                setSelectedItems(that, keys, items, isSelectAll);
                                updateSelectedItems(that)
                            });
                            return deferred
                        }
                        else
                            return that._selectedItemKeys
                    },
                    getSelectedRowKeys: function() {
                        return this.selectedItemKeys()
                    },
                    selectRows: function(keys) {
                        return this.selectedItemKeys(keys)
                    },
                    selectRowsByIndexes: function(indexes) {
                        var items = this.getController('data').items(),
                            i,
                            keys = [];
                        if (!utils.isArray(indexes))
                            indexes = Array.prototype.slice.call(arguments, 0);
                        $.each(indexes, function() {
                            var item = items[this];
                            if (item && item.rowType === 'data')
                                keys.push(item.key)
                        });
                        return this.selectRows(keys)
                    },
                    getSelectedRowsData: function() {
                        return this._selectedItems
                    },
                    changeItemSelection: function(itemIndex, keys) {
                        var that = this,
                            dataController = that.getController('data'),
                            items = dataController.items(),
                            item = items[itemIndex],
                            itemData = item && item.data,
                            selectionMode = that.option(SELECTION_MODE),
                            isSelectedItemsChanged,
                            isSelected,
                            itemKey;
                        if (isSelectable(selectionMode) && isDataItem(item)) {
                            itemKey = dataController.keyOf(itemData);
                            keys = keys || {};
                            if (that.isSelectionWithCheckboxes())
                                keys.control = true;
                            if (keys.shift && selectionMode === 'multiple' && that._focusedItemIndex >= 0)
                                isSelectedItemsChanged = changeItemSelectionWhenShiftKeyPressed(that, itemIndex, items);
                            else if (keys.control) {
                                resetItemSelectionWhenShiftKeyPressed(that);
                                isSelected = that.isSelectedItem(itemKey);
                                if (selectionMode === 'single')
                                    clearSelectedItems(that);
                                if (isSelected)
                                    removeSelectedItem(that, itemKey);
                                else
                                    addSelectedItem(that, itemData);
                                isSelectedItemsChanged = true
                            }
                            else {
                                resetItemSelectionWhenShiftKeyPressed(that);
                                if (that._selectedItemKeys.length !== 1 || !equalKeys(that._selectedItemKeys[0], itemKey)) {
                                    setSelectedItems(that, [itemKey], [itemData]);
                                    isSelectedItemsChanged = true
                                }
                            }
                            if (isSelectedItemsChanged) {
                                that._focusedItemIndex = itemIndex;
                                updateSelectedItems(that);
                                return true
                            }
                        }
                        return false
                    },
                    focusedItemIndex: function(itemIndex) {
                        var that = this;
                        if (utils.isDefined(itemIndex))
                            that._focusedItemIndex = itemIndex;
                        else
                            return that._focusedItemIndex
                    },
                    isSelectionWithCheckboxes: function() {
                        var selectionMode = this.option(SELECTION_MODE),
                            showCheckboxesMode = this.option(SHOW_CHECKBOXES_MODE);
                        return selectionMode === 'multiple' && (showCheckboxesMode === 'always' || this._isSelectionWithCheckboxes)
                    },
                    startSelectionWithCheckboxes: function() {
                        var that = this,
                            isSelectColumnVisible = that.isSelectColumnVisible();
                        if (that.option(SELECTION_MODE) === 'multiple' && !that.isSelectionWithCheckboxes()) {
                            that._isSelectionWithCheckboxes = true;
                            if (isSelectColumnVisible !== that.isSelectColumnVisible())
                                that.getController('columns').updateColumns();
                            else if (that.option(SHOW_CHECKBOXES_MODE) === 'onClick')
                                updateSelectedItems(that);
                            return true
                        }
                        return false
                    },
                    stopSelectionWithCheckboxes: function() {
                        var that = this,
                            isSelectColumnVisible = that.isSelectColumnVisible();
                        if (that._isSelectionWithCheckboxes) {
                            that._isSelectionWithCheckboxes = false;
                            if (isSelectColumnVisible !== that.isSelectColumnVisible())
                                that.getController('columns').updateColumns();
                            return true
                        }
                        return false
                    }
                }
        }());
        dataGrid.registerModule('selection', {
            defaultOptions: function() {
                return {
                        selection: {
                            mode: 'none',
                            showCheckBoxesInMultipleMode: 'onClick',
                            allowSelectAll: true
                        },
                        selectionChanged: null,
                        selectedRowKeys: []
                    }
            },
            controllers: {selection: dataGrid.SelectionController},
            extenders: {
                controllers: {
                    data: {
                        setDataSource: function(dataSource) {
                            this.callBase(dataSource);
                            this.getController('selection').refresh()
                        },
                        pageIndex: function(value) {
                            var that = this,
                                dataSource = that._dataSource;
                            if (dataSource && value && dataSource.pageIndex() !== value)
                                that.getController('selection').focusedItemIndex(-1);
                            return that.callBase(value)
                        },
                        _processDataItem: function() {
                            var that = this,
                                selectionController = that.getController('selection'),
                                hasSelectColumn = selectionController.isSelectColumnVisible(),
                                dataItem = this.callBase.apply(this, arguments);
                            dataItem.isSelected = selectionController.isSelectedItem(dataItem.key);
                            if (hasSelectColumn && dataItem.values)
                                dataItem.values[0] = dataItem.isSelected;
                            return dataItem
                        }
                    },
                    columns: {getVisibleColumns: function() {
                            var that = this,
                                selectionController = that.getController('selection'),
                                columns = that.callBase();
                            columns = $.grep(columns, function(column) {
                                return column.command !== 'select'
                            });
                            if (selectionController.isSelectColumnVisible() && columns.length)
                                columns.unshift({
                                    visible: true,
                                    command: 'select',
                                    dataType: 'boolean',
                                    alignment: 'center',
                                    width: 70
                                });
                            return columns
                        }}
                },
                views: {
                    columnHeadersView: {
                        _renderCore: function(options) {
                            var that = this;
                            that.getController('selection').selectionChanged.remove(that._selectionChangedHandler);
                            that.callBase(options)
                        },
                        _renderHeaderContent: function(rootElement, column, columnIndex) {
                            var that = this,
                                groupElement,
                                selectionController = that.getController('selection');
                            var getSelectAllValue = function(selectionController) {
                                    if (selectionController.isSelectAll() || selectionController.getSelectedRowKeys().length === 0)
                                        return selectionController.isSelectAll()
                                };
                            if (column.command === 'select') {
                                rootElement.addClass(DATAGRID_EDITOR_CELL_CLASS);
                                groupElement = $('<div />').addClass(DATAGRID_CHECKBOX_SIZE_CLASS).dxCheckBox({
                                    value: getSelectAllValue(selectionController),
                                    valueChangeAction: function(e) {
                                        if (e.jQueryEvent && getSelectAllValue(selectionController) !== e.value) {
                                            if (e.previousValue === undefined || e.previousValue) {
                                                selectionController.clearSelection();
                                                e.component.option('value', false)
                                            }
                                            if (e.previousValue === false)
                                                if (that.option("selection.allowSelectAll"))
                                                    selectionController.selectAll();
                                                else
                                                    e.component.option('value', false);
                                            e.jQueryEvent.preventDefault()
                                        }
                                    },
                                    rtlEnabled: that.option('rtlEnabled')
                                }).appendTo(rootElement);
                                rootElement.on('dxclick', that.createAction(function(e) {
                                    var event = e.jQueryEvent;
                                    if (!$(event.target).closest('.dx-checkbox').length)
                                        $(event.currentTarget).children().trigger('dxclick');
                                    event.preventDefault()
                                }));
                                that._selectionChangedHandler = function() {
                                    groupElement.dxCheckBox('instance').option('value', getSelectAllValue(selectionController))
                                };
                                selectionController.selectionChanged.add(that._selectionChangedHandler)
                            }
                            else
                                that.callBase(rootElement, column, columnIndex)
                        }
                    },
                    rowsView: {
                        _getDefaultTemplate: function(column) {
                            var that = this;
                            if (column.command === 'select')
                                return function(container, options) {
                                        container.addClass(DATAGRID_EDITOR_CELL_CLASS);
                                        container.on('dxclick', that.createAction(function(e) {
                                            var selectionController = that.getController('selection'),
                                                event = e.jQueryEvent,
                                                rowIndex = that.getRowIndex($(event.currentTarget).closest('.dx-row'));
                                            if (rowIndex >= 0) {
                                                selectionController.startSelectionWithCheckboxes();
                                                selectionController.changeItemSelection(rowIndex, {shift: event.shiftKey})
                                            }
                                        }));
                                        $('<div />').addClass(DATAGRID_CHECKBOX_SIZE_CLASS).addClass(DATAGRID_SELECT_CHECKBOX_CLASS).dxCheckBox({
                                            value: options.value,
                                            rtlEnabled: that.option('rtlEnabled')
                                        }).appendTo(container)
                                    };
                            else
                                return that.callBase(column)
                        },
                        _update: function(change) {
                            var that = this;
                            if (change.changeType === 'updateSelection') {
                                if (that._tableElement.length > 0)
                                    $.each(change.itemIndexes || [], function(_, index) {
                                        var $row,
                                            isSelected;
                                        if (change.items[index]) {
                                            $row = that._getRowElements().eq(index);
                                            isSelected = !!change.items[index].isSelected;
                                            $row.toggleClass(DATAGRID_ROW_SELECTION_CLASS, isSelected);
                                            $row.find('.dx-checkbox').dxCheckBox('option', 'value', isSelected)
                                        }
                                    });
                                that._updateCheckboxesClass()
                            }
                            else
                                that.callBase(change)
                        },
                        _createTable: function() {
                            var that = this,
                                $table = that.callBase();
                            return $table.on(events.addNamespace('dxpointerdown', "dxDataGridRowsView"), that.createAction(function(e) {
                                    that._isTouchEvent = events.isTouchEvent(e.jQueryEvent)
                                })).on(events.addNamespace('dxhold', "dxDataGridRowsView"), {timeout: that.option("selection.longTapTime") || LONG_TAP_TIME}, that.createAction(function(e) {
                                    var selectionController = that.getController('selection'),
                                        event = e.jQueryEvent;
                                    if (that.option(SHOW_CHECKBOXES_MODE) === 'onLongTap')
                                        if (selectionController.isSelectionWithCheckboxes())
                                            selectionController.stopSelectionWithCheckboxes();
                                        else
                                            selectionController.startSelectionWithCheckboxes();
                                    if (that.option(SHOW_CHECKBOXES_MODE) === 'onClick')
                                        $(event.target).closest('.dx-row').find(DATAGRID_SELECT_CHECKBOX_CLASS).parent().trigger('dxclick')
                                })).on('mousedown selectstart', that.createAction(function(e) {
                                    var event = e.jQueryEvent;
                                    if (event.shiftKey)
                                        event.preventDefault()
                                }))
                        },
                        _createRow: function(rowOptions) {
                            var $row = this.callBase(rowOptions);
                            rowOptions && $row.toggleClass(DATAGRID_ROW_SELECTION_CLASS, !!rowOptions.isSelected);
                            return $row
                        },
                        _rowClick: function(rowIndex, event) {
                            var that = this;
                            that.getController('selection').changeItemSelection(rowIndex, {
                                control: event.ctrlKey,
                                shift: event.shiftKey
                            });
                            that.callBase(rowIndex, event)
                        },
                        _renderCore: function(change) {
                            this.callBase(change);
                            this._updateCheckboxesClass()
                        },
                        _updateCheckboxesClass: function() {
                            var selectionController = this.getController('selection');
                            this._element().toggleClass('dx-select-checkboxes-hidden', selectionController.isSelectColumnVisible() && !selectionController.isSelectionWithCheckboxes())
                        }
                    }
                }
            }
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.editorFactory.js */
    (function($, DX) {
        var dataGrid = DX.ui.dataGrid,
            addNamespace = DX.ui.events.addNamespace;
        var FILTERING_TIMEOUT = 700,
            DATAGRID_CHECKBOX_SIZE = 16,
            DATAGRID_MODULE_NAMESPACE = 'dxDataGridEditorFactory',
            DATAGRID_UPDATE_FOCUS_EVENTS = addNamespace('focusout dxpointerdown dxclick', DATAGRID_MODULE_NAMESPACE);
        var DATAGRID_FOCUS_OVERLAY_CLASS = 'dx-datagrid-focus-overlay',
            DATAGRID_FOCUSED_ELEMENT_CLASS = 'dx-focused',
            DATAGRID_CONTENT_CLASS = 'dx-datagrid-content',
            DATAGRID_EDITOR_CELL_CLASS = 'dx-editor-cell';
        dataGrid.EditorFactoryController = dataGrid.Controller.inherit(function() {
            var createCalendarPicker = function($container, options) {
                    $container.dxDateBox({
                        value: options.value(),
                        useCalendar: true,
                        customOverlayCssClass: 'dx-datagrid',
                        formatWidthCalculator: null,
                        rtlEnabled: options.rtlEnabled,
                        disabled: options.disabled
                    });
                    $container.dxDateBox('instance').optionChanged.add(function(optionName, value) {
                        if (optionName === 'value')
                            options.value(value)
                    })
                };
            var createTextBox = function($container, options) {
                    $container.dxTextBox({
                        placeholder: options.placeholder,
                        width: options.width,
                        value: options.value(),
                        valueChangeAction: function(e) {
                            var updateValue = function(e, isTimeout) {
                                    if (!options.validate || options.validate(e.value))
                                        options.value(options.parseValue ? options.parseValue(e.value) || "" : e.value);
                                    else if (!isTimeout)
                                        e.component.option('value', options.value())
                                };
                            window.clearTimeout($container._valueChangeTimeoutID);
                            if (e.jQueryEvent && e.jQueryEvent.type === "keyup")
                                $container._valueChangeTimeoutID = window.setTimeout(function() {
                                    updateValue(e, true)
                                }, FILTERING_TIMEOUT);
                            else if (e.jQueryEvent && e.jQueryEvent.type === 'keydown' && e.jQueryEvent.which === 13)
                                updateValue(e);
                            else
                                updateValue(e)
                        },
                        mode: options.searching ? 'search' : 'text',
                        valueChangeEvent: 'change' + (options.filtering ? ' keyup' : '') + (options.searching ? ' search' : ''),
                        rtlEnabled: options.rtlEnabled,
                        disabled: options.disabled
                    })
                };
            var createBooleanEditor = function($container, options) {
                    if (options.filtering)
                        createSelectBox($container, $.extend({lookup: {
                                displayExpr: function(data) {
                                    if (data === true)
                                        return options.trueText || 'true';
                                    else if (data === false)
                                        return options.falseText || 'false'
                                },
                                items: [true, false],
                                rtlEnabled: options.rtlEnabled,
                                disabled: options.disabled
                            }}, options));
                    else
                        $container.dxCheckBox({
                            height: DATAGRID_CHECKBOX_SIZE,
                            width: DATAGRID_CHECKBOX_SIZE,
                            value: options.value() || false,
                            valueChangeAction: function(e) {
                                options.value(e.value)
                            },
                            rtlEnabled: options.rtlEnabled
                        })
                };
            var createSelectBox = function($container, options) {
                    var lookup = options.lookup,
                        items,
                        displayGetter;
                    if (lookup) {
                        items = lookup.items;
                        displayGetter = DX.data.utils.compileGetter(lookup.displayExpr);
                        if (options.filtering && items) {
                            items = items.slice(0);
                            items.unshift(null)
                        }
                        $container.dxSelectBox({
                            value: options.value() || null,
                            valueExpr: options.lookup.valueExpr,
                            showClearButton: lookup.allowClearing && !options.filtering,
                            displayExpr: function(data) {
                                if (data === null)
                                    return options.showAllText;
                                return displayGetter(data)
                            },
                            items: items,
                            valueChangeAction: function(e) {
                                options.value(e.value)
                            },
                            rtlEnabled: options.rtlEnabled,
                            disabled: options.disabled
                        })
                    }
                };
            return {
                    _updateFocusCore: function() {
                        var $focus = this._$focusedElement,
                            $dataGridElement = this.component && this.component._element();
                        if ($dataGridElement) {
                            $focus = $dataGridElement.find('[tabindex]:focus, input:focus');
                            if ($focus.length) {
                                $focus = $focus.closest('.dx-editor-cell > *, .dx-row > td');
                                if ($focus.length) {
                                    this.focus($focus);
                                    return
                                }
                            }
                        }
                        this.loseFocus()
                    },
                    _updateFocus: function(e) {
                        var that = this,
                            isFocusOverlay = e.jQueryEvent && $(e.jQueryEvent.target).hasClass(DATAGRID_FOCUS_OVERLAY_CLASS);
                        that._isFocusOverlay = that._isFocusOverlay || isFocusOverlay;
                        clearTimeout(that._updateFocusTimeoutID);
                        that._updateFocusTimeoutID = setTimeout(function() {
                            delete that._updateFocusTimeoutID;
                            if (!that._isFocusOverlay)
                                that._updateFocusCore();
                            that._isFocusOverlay = false
                        })
                    },
                    focus: function($element) {
                        var that = this;
                        if ($element === undefined)
                            return that._$focusedElement;
                        else if ($element)
                            setTimeout(function() {
                                var $focusOverlay = that._$focusOverlay = that._$focusOverlay || $('<div>').addClass(DATAGRID_FOCUS_OVERLAY_CLASS);
                                var align = !parseInt($element.css('border-left-width')) && parseInt($element.css('border-right-width')) ? "right bottom" : "left top";
                                $focusOverlay.show();
                                $focusOverlay.css('visibility', 'hidden');
                                $focusOverlay.appendTo($element.closest('.' + DATAGRID_CONTENT_CLASS));
                                $focusOverlay.outerWidth($element.outerWidth() + 1);
                                $focusOverlay.outerHeight($element.outerHeight() + 1);
                                DX.position($focusOverlay, {
                                    my: align,
                                    at: align,
                                    of: $element
                                });
                                $focusOverlay.css('visibility', 'visible');
                                that._$focusedElement && that._$focusedElement.removeClass(DATAGRID_FOCUSED_ELEMENT_CLASS);
                                $element.addClass(DATAGRID_FOCUSED_ELEMENT_CLASS);
                                that._$focusedElement = $element
                            })
                    },
                    loseFocus: function() {
                        this._$focusedElement && this._$focusedElement.removeClass(DATAGRID_FOCUSED_ELEMENT_CLASS);
                        this._$focusedElement = null;
                        this._$focusOverlay && this._$focusOverlay.hide()
                    },
                    init: function() {
                        var that = this,
                            $container = that.component && that.component._element();
                        $(document).on(DATAGRID_UPDATE_FOCUS_EVENTS, this.createAction($.proxy(this._updateFocus, this)));
                        $container && $container.on('dxclick', '.' + DATAGRID_FOCUS_OVERLAY_CLASS, function(e) {
                            var $focusOverlay = $(e.target),
                                element;
                            $focusOverlay.hide();
                            element = document.elementFromPoint(e.pageX, e.pageY);
                            $focusOverlay.show();
                            $(element).trigger('dxclick');
                            that._$focusedElement && that._$focusedElement.find('input').focus()
                        })
                    },
                    dispose: function() {
                        $(document).off(DATAGRID_UPDATE_FOCUS_EVENTS)
                    },
                    createEditor: function($container, options) {
                        var userCreateEditor = this.option('createEditor');
                        options.rtlEnabled = this.option('rtlEnabled');
                        options.disabled = this.option("disabled");
                        if (userCreateEditor && userCreateEditor($container, options))
                            return;
                        if (options.lookup)
                            createSelectBox($container, options);
                        else
                            switch (options.dataType) {
                                case'date':
                                    createCalendarPicker($container, options);
                                    break;
                                case'boolean':
                                    createBooleanEditor($container, options);
                                    break;
                                default:
                                    createTextBox($container, options);
                                    break
                            }
                    }
                }
        }());
        $.extend(dataGrid.__internals, {DATAGRID_FOCUSED_ELEMENT_CLASS: DATAGRID_FOCUSED_ELEMENT_CLASS});
        dataGrid.registerModule('editorFactory', {
            defaultOptions: function() {
                return {createEditor: null}
            },
            controllers: {editorFactory: dataGrid.EditorFactoryController}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.columnChooserModule.js */
    (function($, DX) {
        var ui = DX.ui,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var DATAGRID_COLUMN_CHOOSER_CLASS = 'dx-datagrid-column-chooser',
            DATAGRID_COLUMN_CHOOSER_BUTTON_CLASS = 'dx-datagrid-column-chooser-button',
            DATAGRID_COLUMN_CHOOSER_ICON_NAME = 'column-chooser',
            DATAGRID_COLUMN_CHOOSER_ITEM_CLASS = "dx-column-chooser-item",
            DATAGRID_COLUMN_CHOOSER_MESSAGE_CLASS = "dx-column-chooser-message",
            DATAGRID_HEADERS_ACTION_CLASS = "dx-datagrid-action-cursor";
        dataGrid.ColumnChooserView = dataGrid.View.inherit({
            _updateItems: function() {
                var hiddenColumns = this._columnsController.getHiddenColumns(),
                    columnChooserOptions = this.option("columnChooser"),
                    $content = this._popupContainer.content();
                $content.dxScrollable(dataGrid.createScrollableOptions(this));
                this._renderColumnChooserItems($content, hiddenColumns);
                if (!hiddenColumns.length)
                    $('<span />').addClass(DATAGRID_COLUMN_CHOOSER_MESSAGE_CLASS).text(columnChooserOptions ? columnChooserOptions.emptyPanelText : "").appendTo($content.dxScrollable("instance").content())
            },
            _initializePopupContainer: function() {
                var that = this,
                    $element = this._element().addClass(DATAGRID_COLUMN_CHOOSER_CLASS),
                    columnChooserOptions = this.option("columnChooser"),
                    isGenericTheme = DevExpress.ui.themes.current().indexOf("generic") > -1;
                if (!utils.isDefined(this._popupContainer)) {
                    this._popupContainer = $element.dxPopup({
                        visible: false,
                        shading: false,
                        closeButton: isGenericTheme,
                        cancelButton: !isGenericTheme,
                        width: columnChooserOptions.width,
                        height: columnChooserOptions.height,
                        title: columnChooserOptions.title,
                        targetContainer: this._element().parent(),
                        rtlEnabled: this.option('rtlEnabled')
                    }).data('dxPopup');
                    this._popupContainer.optionChanged.add(function(optionName) {
                        if (optionName === "visible")
                            that.renderCompleted.fire()
                    })
                }
            },
            _renderCore: function() {
                if (this.option("columnChooser.enabled"))
                    this._initializePopupContainer();
                if (this._popupContainer)
                    this._updateItems()
            },
            _renderColumnChooserItems: function($container, hiddenColumns) {
                var dxScrollable = $container.dxScrollable("instance"),
                    $scrollableContainer = dxScrollable.content(),
                    $item;
                $scrollableContainer.empty();
                $.each(hiddenColumns, function(index, hiddenColumn) {
                    $item = $('<div />').addClass(hiddenColumn.cssClass).addClass(DATAGRID_COLUMN_CHOOSER_ITEM_CLASS).toggleClass(DATAGRID_HEADERS_ACTION_CLASS, hiddenColumn.allowHiding).text(hiddenColumn.caption).appendTo($scrollableContainer)
                });
                dxScrollable.update()
            },
            init: function() {
                var that = this;
                that._columnsController = that.getController('columns');
                that._columnsController.columnsChanged.add(function(e) {
                    if (e.optionName !== 'width')
                        that.render()
                })
            },
            renderShowColumnChooserButton: function(rootElement) {
                var that = this,
                    columnChooserOptions = that.option("columnChooser") || {},
                    $showColumnChooserButton = rootElement.find("." + DATAGRID_COLUMN_CHOOSER_BUTTON_CLASS);
                if (columnChooserOptions.enabled)
                    if (!$showColumnChooserButton.length)
                        $('<div />').addClass(DATAGRID_COLUMN_CHOOSER_BUTTON_CLASS).appendTo(rootElement).dxButton({
                            icon: DATAGRID_COLUMN_CHOOSER_ICON_NAME,
                            clickAction: function(e) {
                                that._popupContainer.toggle(!that._popupContainer.option('visible'))
                            }
                        });
                    else
                        $showColumnChooserButton.show();
                else
                    $showColumnChooserButton.hide()
            },
            getColumnElements: function() {
                var $content = this._popupContainer && this._popupContainer.content();
                return $content && $content.find('.' + DATAGRID_COLUMN_CHOOSER_ITEM_CLASS)
            },
            getName: function() {
                return 'columnChooser'
            },
            getColumns: function() {
                return this._columnsController.getHiddenColumns()
            },
            allowDragging: function(column) {
                var popupContainer = this._popupContainer;
                return popupContainer && popupContainer.option("visible") && column && column.allowHiding
            },
            getBoundingRect: function() {
                var that = this,
                    container = that._popupContainer && that._popupContainer._container(),
                    offset;
                if (container && container.is(':visible')) {
                    offset = container.offset();
                    return {
                            left: offset.left,
                            top: offset.top,
                            right: offset.left + container.outerWidth(),
                            bottom: offset.top + container.outerHeight()
                        }
                }
                return null
            },
            showColumnChooser: function() {
                this._isPopupContainerShown = true;
                if (!this._popupContainer) {
                    this._initializePopupContainer();
                    this.render()
                }
                this._popupContainer.show()
            },
            hideColumnChooser: function() {
                if (this._popupContainer) {
                    this._popupContainer.hide();
                    this._isPopupContainerShown = false
                }
            },
            publicMethods: function() {
                return ['showColumnChooser', 'hideColumnChooser']
            }
        });
        $.extend(dataGrid.__internals, {
            DATAGRID_COLUMN_CHOOSER_CLASS: DATAGRID_COLUMN_CHOOSER_CLASS,
            DATAGRID_COLUMN_CHOOSER_ITEM_CLASS: DATAGRID_COLUMN_CHOOSER_ITEM_CLASS,
            DATAGRID_COLUMN_CHOOSER_BUTTON_CLASS: DATAGRID_COLUMN_CHOOSER_BUTTON_CLASS,
            DATAGRID_COLUMN_CHOOSER_MESSAGE_CLASS: DATAGRID_COLUMN_CHOOSER_MESSAGE_CLASS
        });
        dataGrid.registerModule('columnChooser', {
            defaultOptions: function() {
                return {columnChooser: {
                            enabled: false,
                            width: 250,
                            height: 260,
                            title: Globalize.localize("dxDataGrid-columnChooserTitle"),
                            emptyPanelText: Globalize.localize("dxDataGrid-columnChooserEmptyText")
                        }}
            },
            views: {columnChooserView: dataGrid.ColumnChooserView},
            extenders: {views: {headerPanel: {
                        _renderShowColumnChooserButton: function() {
                            this.getView('columnChooserView').renderShowColumnChooserButton(this._element())
                        },
                        _renderCore: function() {
                            this.callBase();
                            this._renderShowColumnChooserButton()
                        },
                        optionChanged: function(name, value, prevValue) {
                            this.callBase(name, value, prevValue);
                            switch (name) {
                                case'columnChooser':
                                    this._renderShowColumnChooserButton();
                                    break
                            }
                        },
                        isVisible: function() {
                            var that = this,
                                columnChooserOptions = that.getView('columnChooserView').option('columnChooser');
                            return that.callBase() || columnChooserOptions && columnChooserOptions.enabled
                        }
                    }}}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.editing.js */
    (function($, DX) {
        var dataGrid = DX.ui.dataGrid,
            events = DX.ui.events,
            addNamespace = events.addNamespace;
        var DATAGRID_LINK_CLASS = "dx-link",
            DATAGRID_EDITOR_CELL_CLASS = "dx-editor-cell",
            DATAGRID_ROW_HOVERED = "dx-datagrid-row-hovered",
            DATAGRID_ROW_SELECTED = "dx-selection",
            DATAGRID_EDIT_ROW = "dx-edit-row",
            DATAGRID_EDIT_BUTTON_CLASS = "dx-edit-button",
            DATAGRID_INSERT_KEY = "__DX_INSERT__",
            DATAGRID_ROW_REMOVED = "dx-row-removed",
            DATAGRID_CELL_MODIFIED = "dx-cell-modified",
            DATAGRID_CELL_HIGHLIGHT_OUTLINE = "dx-highlight-outline",
            DATAGRID_EDITING_NAMESPACE = "dxDataGridEditing",
            DATAGRID_FOCUS_OVERLAY_CLASS = "dx-datagrid-focus-overlay",
            DATAGRID_EDIT_MODE_BATCH = "batch",
            DATAGRID_EDIT_MODE_ROW = "row";
        $.extend(dataGrid.__internals, {
            DATAGRID_LINK_CLASS: DATAGRID_LINK_CLASS,
            DATAGRID_EDITOR_CELL_CLASS: DATAGRID_EDITOR_CELL_CLASS,
            DATAGRID_EDIT_ROW: DATAGRID_EDIT_ROW,
            DATAGRID_EDIT_BUTTON_CLASS: DATAGRID_EDIT_BUTTON_CLASS
        });
        var getEditMode = function(that) {
                var editing = that.option('editing.editMode');
                if (editing === DATAGRID_EDIT_MODE_BATCH)
                    return editing;
                return DATAGRID_EDIT_MODE_ROW
            };
        dataGrid.EditingController = dataGrid.ViewController.inherit(function() {
            var getDataController = function(that) {
                    return that.getController('data')
                };
            var getDefaultEditor = function(that) {
                    return function(container, options) {
                            var $editor = $('<div/>').appendTo(container);
                            that.getController('editorFactory').createEditor($editor, $.extend({}, options.column, {
                                value: function(value) {
                                    if (value === undefined)
                                        return options.value;
                                    else
                                        options.setValue(value)
                                },
                                width: null
                            }))
                        }
                };
            return {
                    init: function() {
                        var that = this;
                        that._editRowIndex = -1;
                        that._editData = [];
                        that._editKeys = [];
                        that._editColumnIndex = -1;
                        that._columnsController = that.getController("columns");
                        if (!that._saveEditorHandler) {
                            that._saveEditorHandler = that.createAction(function(e) {
                                var event = e.jQueryEvent,
                                    visibleColumns,
                                    isEditorPopup,
                                    isFocusOverlay,
                                    $targetCell,
                                    allowEditing,
                                    isDataRow;
                                if (getEditMode(that) === DATAGRID_EDIT_MODE_BATCH)
                                    if (that.isEditing()) {
                                        isEditorPopup = $(event.target).closest('.dx-overlay-wrapper').length;
                                        isFocusOverlay = $(event.target).hasClass(DATAGRID_FOCUS_OVERLAY_CLASS);
                                        isDataRow = $(event.target).closest('.dx-data-row').length;
                                        visibleColumns = that._columnsController.getVisibleColumns();
                                        $targetCell = $(event.target).closest('td');
                                        allowEditing = $targetCell.length && visibleColumns[$targetCell[0].cellIndex].allowEditing;
                                        if ((!isDataRow || isDataRow && !allowEditing) && !isEditorPopup && !isFocusOverlay)
                                            that.closeEditCell()
                                    }
                            });
                            $(document).on('dxclick', that._saveEditorHandler)
                        }
                        that._updateEditButtons()
                    },
                    getEditMode: function() {
                        return getEditMode(this)
                    },
                    hasChanges: function() {
                        return this._editKeys.length
                    },
                    dispose: function() {
                        this.callBase();
                        $(document).off('dxclick', this._saveEditorHandler)
                    },
                    optionChanged: function(name, value, prevValue){},
                    publicMethods: function() {
                        return ['insertRow', 'editRow', 'editCell', 'closeEditCell', 'removeRow', 'saveEditData', 'recoverRow', 'undeleteRow', 'cancelEditData']
                    },
                    refresh: function() {
                        if (getEditMode(this) === DATAGRID_EDIT_MODE_BATCH) {
                            this._editRowIndex = -1;
                            this._editColumnIndex = -1
                        }
                        else
                            this.init()
                    },
                    isEditing: function() {
                        return this._editRowIndex > -1
                    },
                    isEditRow: function(rowIndex) {
                        return this._editRowIndex === rowIndex && this._editColumnIndex === -1
                    },
                    isEditCell: function(rowIndex, columnIndex) {
                        return this._editRowIndex === rowIndex && this._editColumnIndex === columnIndex
                    },
                    processItems: function(items) {
                        var that = this,
                            editKeys = that._editKeys,
                            i,
                            key;
                        that.update();
                        for (i = 0; i < editKeys.length; i++) {
                            key = editKeys[i];
                            if (key && key[DATAGRID_INSERT_KEY] && key.pageIndex === that._pageIndex)
                                items.splice(key.rowIndex, 0, key)
                        }
                        return items
                    },
                    processDataItem: function(item, columns, generateDataValues) {
                        var that = this,
                            editKeys = that._editKeys,
                            editIndex,
                            data,
                            key = item.data[DATAGRID_INSERT_KEY] ? item.data : item.key;
                        editIndex = $.inArray(key, that._editKeys);
                        if (editIndex >= 0) {
                            data = that._editData[editIndex];
                            if (key && key[DATAGRID_INSERT_KEY]) {
                                item.inserted = true;
                                item.key = key;
                                item.data = data
                            }
                            else if (data) {
                                item.modified = true;
                                item.data = $.extend(true, {}, item.data, data);
                                item.modifiedValues = generateDataValues(data, columns)
                            }
                            else
                                item.removed = true
                        }
                    },
                    insertRow: function() {
                        var that = this,
                            dataController = getDataController(that),
                            rowsView = that.getView('rowsView'),
                            insertKey = {
                                pageIndex: dataController.pageIndex(),
                                rowIndex: rowsView ? rowsView.getTopVisibleItemIndex() : 0
                            };
                        that.refresh();
                        if (getEditMode(that) === DATAGRID_EDIT_MODE_ROW)
                            that._editRowIndex = insertKey.rowIndex;
                        insertKey[DATAGRID_INSERT_KEY] = true;
                        that._editKeys.push(insertKey);
                        that._editData.push({});
                        dataController.updateItems()
                    },
                    editRow: function(rowIndex) {
                        var that = this,
                            dataController = getDataController(that);
                        that.init();
                        that._editRowIndex = rowIndex;
                        that._pageIndex = dataController.pageIndex();
                        dataController.updateItems()
                    },
                    editCell: function(rowIndex, columnIndex) {
                        var that = this,
                            editing = that.option('editing'),
                            oldRowIndex = that._editRowIndex,
                            dataController = getDataController(that),
                            visibleColumns = that.getController('columns').getVisibleColumns(),
                            column = visibleColumns[columnIndex],
                            item = dataController.items()[rowIndex];
                        if (editing && editing.editEnabled && getEditMode(that) === DATAGRID_EDIT_MODE_BATCH && item && !item.removed && column && column.allowEditing) {
                            that._editRowIndex = rowIndex;
                            that._editColumnIndex = columnIndex;
                            that._pageIndex = dataController.pageIndex();
                            dataController.updateItems();
                            return true
                        }
                        return false
                    },
                    removeRow: function(rowIndex) {
                        var that = this,
                            editingOptions = that.option("editing"),
                            editingTexts = editingOptions && editingOptions.texts,
                            confirmDeleteTitle = editingTexts && editingTexts.confirmDeleteTitle,
                            isBatchMode = editingOptions && editingOptions.editMode === DATAGRID_EDIT_MODE_BATCH,
                            confirmDeleteMessage = editingTexts && editingTexts.confirmDeleteMessage,
                            dataController = getDataController(that),
                            removeByKey,
                            item = dataController.items()[rowIndex],
                            key = item && item.key;
                        if (item) {
                            removeByKey = function(key) {
                                that.refresh();
                                var editIndex = $.inArray(key, that._editKeys);
                                if (editIndex >= 0)
                                    if (key && key[DATAGRID_INSERT_KEY]) {
                                        that._editKeys.splice(editIndex, 1);
                                        that._editData.splice(editIndex, 1)
                                    }
                                    else
                                        that._editData[editIndex] = null;
                                else {
                                    that._editKeys.push(key);
                                    that._editData.push(null)
                                }
                                if (isBatchMode)
                                    dataController.updateItems();
                                else
                                    that.saveEditData()
                            };
                            if (isBatchMode || !confirmDeleteMessage)
                                removeByKey(key);
                            else
                                DX.ui.dialog.confirm(confirmDeleteMessage, confirmDeleteTitle).done(function(confirmResult) {
                                    if (confirmResult)
                                        removeByKey(key)
                                })
                        }
                    },
                    recoverRow: function(rowIndex) {
                        DX.utils.logger.warn("'recoverRow' method is deprecated since 14.1. Use the 'undeleteRow' method instead.");
                        return this.undeleteRow(rowIndex)
                    },
                    undeleteRow: function(rowIndex) {
                        var that = this,
                            dataController = getDataController(that),
                            item = dataController.items()[rowIndex],
                            key = item && item.key;
                        if (item) {
                            var editIndex = $.inArray(key, that._editKeys);
                            if (editIndex >= 0) {
                                that._editKeys.splice(editIndex, 1);
                                that._editData.splice(editIndex, 1);
                                dataController.updateItems()
                            }
                        }
                    },
                    saveEditData: function() {
                        var that = this;
                        that._editRowIndex = -1;
                        that._editColumnIndex = -1;
                        that._saveEditData()
                    },
                    _saveEditData: function() {
                        var that = this,
                            dataController = getDataController(that),
                            store = dataController.store(),
                            item,
                            key,
                            processedKeys = [],
                            deferreds = [];
                        var removeEditData = function(that, keys) {
                                $.each(keys, function(index, key) {
                                    var editIndex = $.inArray(key, that._editKeys);
                                    if (editIndex >= 0) {
                                        that._editKeys.splice(editIndex, 1);
                                        that._editData.splice(editIndex, 1)
                                    }
                                })
                            };
                        if (that._editKeys.length) {
                            $.each(that._editKeys, function(index, key) {
                                var data = that._editData[index],
                                    deferred;
                                if (!data)
                                    deferred = store.remove(key);
                                else if (key && key[DATAGRID_INSERT_KEY])
                                    deferred = store.insert(data);
                                else
                                    deferred = store.update(key, data);
                                deferred.done($.proxy(processedKeys.push, processedKeys, key));
                                deferreds.push(deferred)
                            });
                            if (deferreds.length)
                                $.when.apply($, deferreds).always(function() {
                                    removeEditData(that, processedKeys);
                                    dataController.refresh()
                                }).fail(function(e) {
                                    dataController.dataErrorOccurred.fire(e)
                                })
                        }
                        else
                            dataController.updateItems()
                    },
                    _updateEditButtons: function() {
                        var that = this,
                            saveChangesButton = that._saveChangesButton,
                            cancelChangesButton = that._cancelChangesButton,
                            hasChanges = that.hasChanges();
                        if (saveChangesButton)
                            saveChangesButton.option('disabled', !hasChanges);
                        if (cancelChangesButton)
                            cancelChangesButton.option('disabled', !hasChanges)
                    },
                    cancelEditData: function() {
                        var that = this,
                            dataController = getDataController(that);
                        that.init();
                        dataController.updateItems()
                    },
                    closeEditCell: function() {
                        var that = this,
                            dataController = getDataController(that);
                        setTimeout(function() {
                            that._editRowIndex = -1;
                            that._editColumnIndex = -1;
                            dataController.updateItems()
                        })
                    },
                    update: function() {
                        var that = this,
                            dataController = getDataController(that);
                        if (that._pageIndex !== dataController.pageIndex()) {
                            that.refresh();
                            that._pageIndex = dataController.pageIndex()
                        }
                        that._updateEditButtons()
                    },
                    updateFieldValue: function(rowKey, dataField, value) {
                        var that = this,
                            editDataIndex;
                        if (rowKey !== undefined) {
                            editDataIndex = $.inArray(rowKey, that._editKeys);
                            if (editDataIndex < 0) {
                                editDataIndex = that._editData.length;
                                that._editData.push({});
                                that._editKeys.push(rowKey)
                            }
                            if (that._editData[editDataIndex])
                                that._editData[editDataIndex][dataField] = value;
                            that._updateEditButtons()
                        }
                    },
                    getColumnTemplate: function(options) {
                        var that = this,
                            column = options.column,
                            template,
                            isRowMode,
                            editingOptions,
                            editingTexts;
                        if (column.allowEditing && column.dataField && !column.command && that._editRowIndex === options.rowIndex && (that._editColumnIndex < 0 || that._editColumnIndex === options.columnIndex) && options.rowType === 'data') {
                            options.setValue = function(value) {
                                that.updateFieldValue(this.key, this.column.dataField, value)
                            };
                            template = column.editCellTemplate || getDefaultEditor(that)
                        }
                        else if (column.command === 'edit')
                            template = function(container, options) {
                                var createLink = function(container, text, methodName, options) {
                                        var $link = $('<a />').addClass(DATAGRID_LINK_CLASS).text(text).on(addNamespace('dxclick', DATAGRID_EDITING_NAMESPACE), that.createAction(function() {
                                                setTimeout(function() {
                                                    that[methodName](options.rowIndex)
                                                })
                                            }));
                                        options.rtlEnabled ? container.prepend($link, "&nbsp;") : container.append($link, "&nbsp;")
                                    };
                                isRowMode = getEditMode(that) === DATAGRID_EDIT_MODE_ROW;
                                container.css('text-align', 'center');
                                options.rtlEnabled = that.option('rtlEnabled');
                                editingOptions = that.option("editing") || {};
                                editingTexts = editingOptions.texts || {};
                                if (that._editRowIndex === options.rowIndex && isRowMode) {
                                    createLink(container, editingTexts.saveRowChanges, 'saveEditData', options);
                                    createLink(container, editingTexts.cancelRowChanges, 'cancelEditData', options)
                                }
                                else {
                                    if (editingOptions.editEnabled && isRowMode)
                                        createLink(container, editingTexts.editRow, 'editRow', options);
                                    if (editingOptions.removeEnabled)
                                        if (options.row.removed)
                                            createLink(container, editingTexts.undeleteRow, 'undeleteRow', options);
                                        else
                                            createLink(container, editingTexts.deleteRow, 'removeRow', options)
                                }
                            };
                        return template
                    },
                    renderEditButtons: function(rootElement) {
                        var that = this,
                            insertButton = rootElement.find('.' + DATAGRID_EDIT_BUTTON_CLASS),
                            editingOptions = that.option("editing") || {};
                        var createEditButton = function(rootElement, className, methodName) {
                                return $('<div />').addClass(DATAGRID_EDIT_BUTTON_CLASS).addClass("dx-datagrid-" + className + "-button").appendTo(rootElement).dxButton({
                                        icon: "edit-button-" + className,
                                        clickAction: $.proxy(that, methodName)
                                    }).dxButton('instance')
                            };
                        if (insertButton.length)
                            insertButton.remove();
                        if ((editingOptions.editEnabled || editingOptions.insertEnabled || editingOptions.removeEnabled) && getEditMode(that) === DATAGRID_EDIT_MODE_BATCH) {
                            that._cancelChangesButton = createEditButton(rootElement, "cancel", 'cancelEditData');
                            that._saveChangesButton = createEditButton(rootElement, "save", 'saveEditData');
                            that._updateEditButtons()
                        }
                        if (editingOptions.insertEnabled)
                            createEditButton(rootElement, "addrow", 'insertRow')
                    }
                }
        }());
        dataGrid.registerModule('editing', {
            defaultOptions: function() {
                return {editing: {
                            editMode: 'row',
                            insertEnabled: false,
                            editEnabled: false,
                            removeEnabled: false,
                            texts: {
                                editRow: Globalize.localize("dxDataGrid-editingEditRow"),
                                saveRowChanges: Globalize.localize("dxDataGrid-editingSaveRowChanges"),
                                cancelRowChanges: Globalize.localize("dxDataGrid-editingCancelRowChanges"),
                                deleteRow: Globalize.localize("dxDataGrid-editingDeleteRow"),
                                recoverRow: Globalize.localize("dxDataGrid-editingUndeleteRow"),
                                undeleteRow: Globalize.localize("dxDataGrid-editingUndeleteRow"),
                                confirmDeleteMessage: Globalize.localize("dxDataGrid-editingConfirmDeleteMessage"),
                                confirmDeleteTitle: Globalize.localize("dxDataGrid-editingConfirmDeleteTitle")
                            }
                        }}
            },
            controllers: {editing: dataGrid.EditingController},
            extenders: {
                controllers: {
                    data: {
                        init: function() {
                            this._editingController = this.getController('editing');
                            this.callBase()
                        },
                        reload: function() {
                            this._editingController.refresh();
                            return this.callBase()
                        },
                        _processItems: function(items) {
                            items = this._editingController.processItems(items);
                            return this.callBase(items)
                        },
                        _processDataItem: function(dataItem, columns) {
                            this._editingController.processDataItem(dataItem, columns, this._generateDataValues);
                            return this.callBase(dataItem, columns)
                        }
                    },
                    columns: {getVisibleColumns: function() {
                            var that = this,
                                editing = that.option('editing'),
                                columns = that.callBase();
                            columns = $.grep(columns, function(column) {
                                return column.command !== 'edit'
                            });
                            if (editing && (editing.editEnabled && getEditMode(that) === DATAGRID_EDIT_MODE_ROW || editing.removeEnabled || editing.insertEnabled) && columns.length)
                                columns.push({
                                    visible: true,
                                    command: 'edit',
                                    width: 100
                                });
                            return columns
                        }}
                },
                views: {
                    rowsView: {
                        _getColumnTemplate: function(options) {
                            var that = this,
                                template = that.getController('editing').getColumnTemplate(options);
                            return template || that.callBase(options)
                        },
                        _createRow: function(options) {
                            var $row = this.callBase(options),
                                editingController,
                                isEditRow,
                                isRowRemoved,
                                isRowInserted,
                                isRowModified;
                            if (options) {
                                editingController = this.getController('editing');
                                isEditRow = editingController.isEditRow(options.rowIndex);
                                isRowRemoved = !!options.removed;
                                isRowInserted = !!options.inserted;
                                isRowModified = !!options.modified;
                                if (getEditMode(this) === DATAGRID_EDIT_MODE_BATCH)
                                    $row.toggleClass(DATAGRID_ROW_REMOVED, isRowRemoved);
                                else
                                    $row.toggleClass(DATAGRID_EDIT_ROW, isEditRow);
                                if (isEditRow || isRowInserted || isRowRemoved || isRowModified) {
                                    $row.removeClass(DATAGRID_ROW_HOVERED);
                                    $row.removeClass(DATAGRID_ROW_SELECTED)
                                }
                            }
                            return $row
                        },
                        _rowClick: function(rowIndex, event) {
                            var that = this,
                                editingController = that.getController('editing'),
                                $targetCell = $(event.target).closest('td'),
                                cellIndex = $targetCell.length ? $targetCell[0].cellIndex : -1;
                            if (cellIndex >= 0 && editingController.editCell(rowIndex, cellIndex))
                                setTimeout(function() {
                                    that._focusEditor()
                                });
                            else if (!editingController.isEditRow(rowIndex))
                                that.callBase(rowIndex, event)
                        },
                        _cellPrepared: function($cell, parameters) {
                            var modifiedValues = parameters.row && (parameters.row.inserted ? parameters.row.values : parameters.row.modifiedValues),
                                columnIndex = parameters.columnIndex,
                                alignment = parameters.column.alignment,
                                editingController = this.getController('editing'),
                                $contents;
                            parameters.isEditing = editingController.isEditCell(parameters.rowIndex, columnIndex) || editingController.isEditRow(parameters.rowIndex) && parameters.column.allowEditing;
                            if (parameters.isEditing) {
                                $cell.addClass(DATAGRID_EDITOR_CELL_CLASS);
                                if (alignment)
                                    $cell.find('input').first().css('text-align', alignment)
                            }
                            if (modifiedValues && parameters.column && parameters.column.allowEditing && modifiedValues[columnIndex] !== undefined)
                                if (!parameters.isEditing) {
                                    $cell.addClass(DATAGRID_CELL_MODIFIED);
                                    $contents = $cell.contents();
                                    $("<div>").addClass(DATAGRID_CELL_HIGHLIGHT_OUTLINE).append(!$contents.length || $contents.length === 1 && !$contents.eq(0).text().length ? "&nbsp;" : $contents).appendTo($cell)
                                }
                            this.callBase.apply(this, arguments)
                        },
                        _update: function(change) {
                            this.callBase(change);
                            if (change.changeType === 'updateSelection')
                                this._element().find('.' + DATAGRID_EDIT_ROW).removeClass(DATAGRID_ROW_SELECTED)
                        },
                        _focusEditor: function() {
                            this._tableElement.find('input').first().focus()
                        }
                    },
                    headerPanel: {
                        _renderCore: function() {
                            this.callBase();
                            this.getController('editing').renderEditButtons(this._element())
                        },
                        isVisible: function() {
                            var that = this,
                                editingOptions = that.getController('editing').option('editing');
                            return that.callBase() || editingOptions && (editingOptions.insertEnabled || (editingOptions.editEnabled || editingOptions.removeEnabled) && editingOptions.editMode === DATAGRID_EDIT_MODE_BATCH)
                        }
                    }
                }
            }
        });
        $.extend(dataGrid.__internals, {
            DATAGRID_CELL_MODIFIED: DATAGRID_CELL_MODIFIED,
            DATAGRID_CELL_HIGHLIGHT_OUTLINE: DATAGRID_CELL_HIGHLIGHT_OUTLINE,
            DATAGRID_FOCUS_OVERLAY_CLASS: DATAGRID_FOCUS_OVERLAY_CLASS
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.dataController.js */
    (function($, DX) {
        var ui = DX.ui,
            dataGrid = ui.dataGrid,
            utils = DX.utils;
        dataGrid.DataController = dataGrid.Controller.inherit({}).include(ui.DataHelperMixin).inherit(function() {
            var processGroupItems = function(that, items, groupsCount) {
                    var scrollingMode = that.option('scrolling.mode'),
                        collectedItems = [],
                        collectItemsCore = function(items, collectedItems, groupIndex, groupsCount, path, collectContinuationItems) {
                            var i,
                                isExpanded,
                                item;
                            if (groupIndex >= groupsCount)
                                collectedItems.push.apply(collectedItems, items);
                            else
                                for (i = 0; i < items.length; i++) {
                                    item = items[i];
                                    if (item.key !== undefined && item.items !== undefined) {
                                        path.push(item.key);
                                        isExpanded = !!item.items;
                                        if (collectContinuationItems || !item.isContinuation)
                                            collectedItems.push({
                                                rowType: 'group',
                                                groupIndex: groupIndex,
                                                data: item,
                                                isExpanded: isExpanded,
                                                values: path.slice(0)
                                            });
                                        if (isExpanded)
                                            collectItemsCore(item.items, collectedItems, groupIndex + 1, groupsCount, path, collectContinuationItems);
                                        path.pop()
                                    }
                                    else
                                        collectedItems.push(item)
                                }
                        };
                    collectItemsCore(items, collectedItems, 0, groupsCount, [], scrollingMode !== 'virtual' && scrollingMode !== 'infinite');
                    return collectedItems
                };
            return {
                    init: function() {
                        var that = this;
                        that._items = [];
                        that._columnsController = that.getController('columns');
                        that._columnsChangedHandler = function(args) {
                            var updateItemsHandler = function() {
                                    that._columnsController.columnsChanged.remove(updateItemsHandler);
                                    that.updateItems()
                                };
                            if (args.changeType === 'sorting' || args.changeType === 'grouping') {
                                if (that._dataSource) {
                                    that._dataSource.group(that._columnsController.getGroupDataSourceParameters());
                                    that._dataSource.sort(that._columnsController.getSortDataSourceParameters());
                                    that.reload()
                                }
                            }
                            else if (args.changeType === 'columns' && args.optionName && (args.optionName === 'filterText' || args.optionName.filterText !== undefined || (args.optionName === 'selectedFilterOperation' || args.optionName.selectedFilterOperation !== undefined) && args.column.filterText))
                                that._applyFilter();
                            else if (args.optionName !== 'width')
                                that._columnsController.columnsChanged.add(updateItemsHandler)
                        };
                        that._gridDataSourceChangedHandler = function(e) {
                            var dataSource = that._dataSource,
                                isDataSourceApplied,
                                additionalFilter;
                            if (dataSource) {
                                that._columnsController.applyDataSource(dataSource);
                                isDataSourceApplied = that._columnsController.isDataSourceApplied();
                                additionalFilter = that._calculateAdditionalFilter();
                                if (that._needApplyFilter && isDataSourceApplied && additionalFilter && additionalFilter.length)
                                    that._applyFilter();
                                else
                                    that.updateItems(e);
                                that._needApplyFilter = !isDataSourceApplied
                            }
                        };
                        that._columnsController.columnsChanged.add(that._columnsChangedHandler);
                        that._loadingChangedHandler = function(isLoading) {
                            that._isLoading = isLoading;
                            that.loadingChanged.fire(that.isLoading())
                        };
                        that._loadErrorHandler = function(e) {
                            that.dataErrorOccurred.fire(e)
                        };
                        that._viewportSize = 20;
                        that._isLoading = false;
                        that._isCustomLoading = false;
                        that._refreshDataSource();
                        that.createAction('dataErrorOccurred', {excludeValidators: ['gesture']});
                        that.dataErrorOccurred.add(function(e) {
                            return that.executeAction('dataErrorOccurred', e)
                        })
                    },
                    callbackNames: function() {
                        return ['changed', 'loadingChanged', 'dataErrorOccurred']
                    },
                    callbackFlags: function(name) {
                        if (name === 'dataErrorOccurred')
                            return 'stopOnFalse'
                    },
                    publicMethods: function() {
                        return ['beginCustomLoading', 'endCustomLoading', 'refresh', 'filter', 'clearFilter', 'keyOf', 'byKey', 'getDataByKeys', 'collapseAll', 'expandAll', 'pageIndex', 'pageSize', 'pageCount', 'totalCount', '_disposeDataSource']
                    },
                    optionChanged: function(name, value, prevValue) {
                        var that = this;
                        switch (name) {
                            case'dataSource':
                            case'grouping':
                            case'scrolling':
                            case'rtlEnabled':
                            case'paging':
                            case'columns':
                                that._columnsController.reset();
                                that._refreshDataSource();
                                break;
                            case'dataErrorOccurred':
                                that.createAction('dataErrorOccurred');
                                break
                        }
                    },
                    _dataSourceType: function() {
                        var scrolling = this.option('scrolling');
                        if (scrolling && (scrolling.mode === 'virtual' || scrolling.mode === 'infinite'))
                            return dataGrid.ScrollingDataSourceWrapper;
                        else
                            return dataGrid.DataSource
                    },
                    _dataSourceOptions: function() {
                        var that = this,
                            paging = that.option('paging'),
                            scrolling = that.option('scrolling'),
                            virtualMode = !!(scrolling && scrolling.mode === 'virtual'),
                            appendMode = !!(scrolling && scrolling.mode === 'infinite');
                        return {
                                paginate: paging && paging.enabled || virtualMode || appendMode,
                                loadingTimeout: that.option('loadingTimeout'),
                                asyncLoadEnabled: true,
                                pageIndex: paging && paging.pageIndex,
                                pageSize: paging && paging.pageSize,
                                requireTotalCount: !appendMode,
                                useNativeGrouping: 'auto',
                                scrolling: scrolling
                            }
                    },
                    _initDataSource: function() {
                        var columnsController = this._columnsController,
                            sort,
                            group,
                            dataSource;
                        if (this.option("dataSource") instanceof DX.data.DataSource) {
                            DX.utils.logger.error("The dataSource option cannot take the DevExpress.data.DataSource instance directly. Assign a DataSource configuration object (see http://js.devexpress.com/Documentation/ApiReference/Data_Library/DataSource/Configuration) or a simple array instead.");
                            return
                        }
                        this.callBase();
                        dataSource = this._dataSource;
                        if (dataSource) {
                            columnsController.updateSortingGrouping(dataSource);
                            sort = columnsController.getSortDataSourceParameters();
                            if (sort)
                                dataSource.sort(sort);
                            group = columnsController.getGroupDataSourceParameters();
                            if (group)
                                dataSource.group(group);
                            this.setDataSource(dataSource)
                        }
                    },
                    _processItems: function(items) {
                        var that = this,
                            visibleColumns = that._columnsController.getVisibleColumns(),
                            groupColumns = that._columnsController.getVisibleGroupColumns(),
                            result = [],
                            dataIndex = 0;
                        if (items.length > 0 && that._columnsController.isInitialized()) {
                            if (groupColumns.length > 0)
                                items = processGroupItems(that, items, groupColumns.length);
                            $.each(items, function(index, item) {
                                if (utils.isDefined(item)) {
                                    if (utils.isDefined(item.groupIndex))
                                        dataIndex = 0;
                                    else {
                                        item = that._generateDataItem(item);
                                        item = that._processDataItem(item, visibleColumns);
                                        item.dataIndex = dataIndex++
                                    }
                                    result.push(item)
                                }
                            })
                        }
                        return result
                    },
                    _generateDataItem: function(data) {
                        return {
                                rowType: 'data',
                                data: data,
                                key: this.keyOf(data)
                            }
                    },
                    _processDataItem: function(dataItem, visibleColumns) {
                        dataItem.values = this._generateDataValues(dataItem.data, visibleColumns);
                        return dataItem
                    },
                    _generateDataValues: function(data, columns) {
                        var values = [];
                        $.each(columns, function() {
                            var value = null;
                            if (utils.isDefined(this.groupIndex))
                                value = null;
                            else if (this.calculateCellValue)
                                value = this.calculateCellValue(data);
                            else if (this.dataField)
                                value = data[this.dataField];
                            values.push(value)
                        });
                        return values
                    },
                    _updateItemsCore: function(change) {
                        var that = this,
                            items,
                            dataSource = that._dataSource,
                            changes = [],
                            changeType = change.changeType;
                        if (dataSource) {
                            items = change.items || dataSource.items();
                            items = that._processItems(items.slice(0));
                            change.items = items;
                            change.changeType = changeType || 'refresh';
                            switch (changeType) {
                                case'prepend':
                                    that._items.unshift.apply(that._items, items);
                                    break;
                                case'append':
                                    that._items.push.apply(that._items, items);
                                    break;
                                default:
                                    that._items = items;
                                    break
                            }
                        }
                    },
                    updateItems: function(change) {
                        var that = this;
                        change = change || {};
                        if (that._dataSource && that._columnsController.isDataSourceApplied()) {
                            that._updateItemsCore(change);
                            that.changed.fire(change)
                        }
                    },
                    changeGroupExpand: function(path) {
                        this._dataSource && this._dataSource.changeGroupExpand(path)
                    },
                    getGroupPathByRowIndex: function(rowIndex) {
                        var item = this.items()[rowIndex];
                        if (item && item.rowType === 'group')
                            return item.values
                    },
                    isLoading: function() {
                        return this._isLoading || this._isCustomLoading
                    },
                    _calculateAdditionalFilter: function() {
                        return null
                    },
                    _applyFilter: function() {
                        var that = this,
                            dataSource = that._dataSource,
                            additionalFilter,
                            filter = that._filter;
                        if (dataSource) {
                            additionalFilter = that._calculateAdditionalFilter();
                            if (additionalFilter)
                                if (filter)
                                    filter = [filter, 'and', additionalFilter];
                                else
                                    filter = additionalFilter;
                            dataSource.filter(filter && filter.length ? filter : null);
                            dataSource.pageIndex(0);
                            return that.reload()
                        }
                    },
                    filter: function(filterExpr) {
                        this._filter = arguments.length > 1 ? Array.prototype.slice.call(arguments, 0) : filterExpr;
                        this._applyFilter()
                    },
                    clearFilter: function() {
                        this._filter = null;
                        this._applyFilter()
                    },
                    setDataSource: function(dataSource) {
                        var that = this;
                        if (that._dataSource) {
                            that._dataSource.changed.remove(that._gridDataSourceChangedHandler);
                            that._dataSource.loadingChanged.remove(that._loadingChangedHandler);
                            that._dataSource.loadError.remove(that._loadErrorHandler)
                        }
                        that._dataSource = dataSource;
                        if (dataSource) {
                            that._isLoading = !dataSource.isLoaded();
                            that._filter = dataSource.filter();
                            dataSource.changed.add(that._gridDataSourceChangedHandler);
                            dataSource.loadingChanged.add(that._loadingChangedHandler);
                            dataSource.loadError.add(that._loadErrorHandler);
                            that._needApplyFilter = true;
                            if (dataSource.isLoaded())
                                that._gridDataSourceChangedHandler()
                        }
                    },
                    items: function() {
                        return this._items
                    },
                    virtualItemsCount: function() {
                        var dataSource = this._dataSource;
                        return dataSource && dataSource.virtualItemsCount && dataSource.virtualItemsCount()
                    },
                    setViewportSize: function(size) {
                        var dataSource = this._dataSource;
                        return dataSource && dataSource.setViewportSize && dataSource.setViewportSize(size)
                    },
                    setViewportItemIndex: function(itemIndex) {
                        var dataSource = this._dataSource;
                        dataSource && dataSource.setViewportItemIndex && dataSource.setViewportItemIndex(itemIndex)
                    },
                    collapseAll: function(groupIndex) {
                        var dataSource = this._dataSource;
                        if (dataSource && dataSource.collapseAll(groupIndex)) {
                            dataSource.pageIndex(0);
                            dataSource.reload()
                        }
                    },
                    expandAll: function(groupIndex) {
                        var dataSource = this._dataSource;
                        if (dataSource && dataSource.expandAll(groupIndex)) {
                            dataSource.pageIndex(0);
                            dataSource.reload()
                        }
                    },
                    totalItemsCount: function() {
                        return this._dataSource ? this._dataSource.totalItemsCount() : 0
                    },
                    hasKnownLastPage: function() {
                        return this._dataSource ? this._dataSource.hasKnownLastPage() : true
                    },
                    isLoaded: function() {
                        return this._dataSource ? this._dataSource.isLoaded() : false
                    },
                    totalCount: function() {
                        return this._dataSource ? this._dataSource.totalCount() : 0
                    },
                    pageCount: function() {
                        return this._dataSource ? this._dataSource.pagesCount() : 1
                    },
                    dataSource: function() {
                        return this._dataSource
                    },
                    store: function() {
                        var dataSource = this._dataSource;
                        return dataSource && dataSource.store()
                    },
                    keyOf: function(data) {
                        var store = this.store();
                        return store && store.keyOf(data)
                    },
                    byKey: function(key) {
                        var store = this.store(),
                            result;
                        if (!store)
                            return;
                        $.each(this._items, function(_, item) {
                            if (item.key === key) {
                                result = $.Deferred().resolve(item.data);
                                return false
                            }
                        });
                        return result || store.byKey(key)
                    },
                    getDataByKeys: function(rowKeys) {
                        var that = this,
                            result = $.Deferred(),
                            deferreds = [],
                            data = [];
                        $.each(rowKeys, function(index, key) {
                            deferreds.push(that.byKey(key).done(function(keyData) {
                                data[index] = keyData
                            }))
                        });
                        $.when.apply($, deferreds).always(function() {
                            result.resolve(data)
                        });
                        return result
                    },
                    pageIndex: function(value) {
                        var that = this,
                            dataSource = that._dataSource;
                        if (dataSource) {
                            if (value !== undefined)
                                if (dataSource.pageIndex() !== value) {
                                    dataSource.pageIndex(value);
                                    return dataSource.load()
                                }
                            return dataSource.pageIndex()
                        }
                        return 0
                    },
                    pageSize: function(value) {
                        var that = this,
                            dataSource = that._dataSource;
                        if (value === undefined)
                            return dataSource ? dataSource.pageSize() : 0;
                        if (dataSource) {
                            dataSource.pageIndex(0);
                            dataSource.pageSize(value);
                            return dataSource.reload()
                        }
                    },
                    beginCustomLoading: function(messageText) {
                        var that = this;
                        that._isCustomLoading = true;
                        that.loadingChanged.fire(that.isLoading(), messageText)
                    },
                    endCustomLoading: function() {
                        var that = this;
                        that._isCustomLoading = false;
                        that.loadingChanged.fire(that.isLoading())
                    },
                    refresh: function() {
                        var that = this,
                            d = $.Deferred();
                        $.when(this._columnsController.refresh()).always(function() {
                            $.when(that.reload()).done(d.resolve).fail(d.reject)
                        });
                        return d
                    },
                    reload: function() {
                        var dataSource = this._dataSource;
                        return dataSource && dataSource.reload()
                    },
                    dispose: function() {
                        var that = this,
                            dataSource = that._dataSource;
                        that.callBase();
                        if (dataSource) {
                            dataSource.changed.remove(that._gridDataSourceChangedHandler);
                            dataSource.loadingChanged.remove(that._loadingChangedHandler)
                        }
                    }
                }
        }());
        dataGrid.registerModule('data', {
            defaultOptions: function() {
                return {
                        dataSource: null,
                        dataErrorOccurred: null
                    }
            },
            controllers: {data: ui.dataGrid.DataController}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.columnsView.js */
    (function($, DX, undefined) {
        var ui = DX.ui,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var DATAGRID_SORT_CLASS = "dx-sort",
            DATAGRID_SORTUP_CLASS = "dx-sort-up",
            DATAGRID_SORTDOWN_CLASS = "dx-sort-down",
            DATAGRID_CELL_CONTENT_CLASS = "dx-datagrid-text-content",
            DATAGRID_TABLE_CONTENT_CLASS = "dx-datagrid-table-content",
            DATAGRID_ROW_CLASS = "dx-row",
            DATAGRID_GROUP_ROW_CLASS = "dx-group-row",
            DATAGRID_TABLE_CLASS = "dx-datagrid-table";
        dataGrid.ColumnsView = dataGrid.View.inherit({
            _applySorting: function(rootElement, column) {
                function getAlignment(columnAlignment) {
                    return columnAlignment === 'right' ? 'left' : 'right'
                }
                rootElement.find('.' + DATAGRID_SORT_CLASS).remove();
                if (utils.isDefined(column.sortOrder)) {
                    if (column.alignment === 'center') {
                        var align = this.option('rtlEnabled') ? 'right' : 'left';
                        $('<span />').addClass(DATAGRID_SORT_CLASS).css('float', align).prependTo(rootElement)
                    }
                    $('<span />').addClass(DATAGRID_SORT_CLASS).css('float', getAlignment(column.alignment)).toggleClass(DATAGRID_SORTUP_CLASS, column.sortOrder === 'asc').toggleClass(DATAGRID_SORTDOWN_CLASS, column.sortOrder === 'desc').prependTo(rootElement)
                }
            },
            _updateSortIndicatorPositions: function(rootElement) {
                if (!rootElement)
                    return;
                var sortIndicators = rootElement.find('.' + DATAGRID_SORT_CLASS);
                $.each(sortIndicators, function() {
                    var $sortIndicator = $(this),
                        $sortIndicatorContainer = $sortIndicator.parent(),
                        $textContent = $sortIndicatorContainer.find('.' + DATAGRID_CELL_CONTENT_CLASS);
                    $sortIndicator.height($textContent.height() || $sortIndicatorContainer.height())
                })
            },
            _createRow: function() {
                return $("<tr />").addClass(DATAGRID_ROW_CLASS)
            },
            _createTable: function() {
                return $('<table />').toggleClass(DATAGRID_TABLE_CLASS, !this.option('columnAutoWidth'))
            },
            init: function() {
                var that = this;
                that._columnsController = that.getController('columns')
            },
            getColumnWidths: function() {
                var that = this,
                    cells,
                    result = [],
                    width,
                    clientRect;
                if (that._tableElement) {
                    cells = that._tableElement.find('tr').filter(':not(.' + DATAGRID_GROUP_ROW_CLASS + ')').first().find('td');
                    $.each(cells, function(index, item) {
                        if (item.getBoundingClientRect) {
                            clientRect = item.getBoundingClientRect();
                            width = Math.floor(clientRect.right - clientRect.left)
                        }
                        else
                            width = $(item).outerWidth(true);
                        result.push(width)
                    })
                }
                return result
            },
            setColumnWidths: function(widths) {
                this._setColumnWidthsCore(this._tableElement, widths)
            },
            _setColumnWidthsCore: function(tableElements, widths) {
                var colgroupElement,
                    i,
                    columnIndex;
                if (!tableElements)
                    return;
                for (i = 0; i < tableElements.length; i++) {
                    tableElements.eq(i).addClass(DATAGRID_TABLE_CLASS);
                    if (widths) {
                        this._columnWidths = widths;
                        colgroupElement = tableElements.eq(i).find('colgroup').first();
                        colgroupElement.empty();
                        for (columnIndex = 0; columnIndex < widths.length; columnIndex++)
                            $('<col />').width(widths[columnIndex] || 'auto').appendTo(colgroupElement)
                    }
                }
            },
            resetColumnWidths: function() {
                var that = this,
                    tableElement,
                    visibleColumns = that._columnsController.getVisibleColumns(),
                    i,
                    widths = [],
                    $elementWithFocus;
                for (i = 0; i < visibleColumns.length; i++)
                    widths.push(visibleColumns[i].width);
                that.setColumnWidths(widths);
                if (that._tableElement) {
                    $elementWithFocus = that._tableElement.find(':focus');
                    tableElement = that._createTable();
                    tableElement.append(that._tableElement.children());
                    tableElement.toggleClass(DATAGRID_TABLE_CONTENT_CLASS, that._tableElement.hasClass(DATAGRID_TABLE_CONTENT_CLASS));
                    tableElement.attr('style', that._tableElement.attr('style'));
                    that._tableElement.replaceWith(tableElement);
                    that._tableElement = tableElement;
                    $elementWithFocus.focus()
                }
            },
            getColumnElements: function(){},
            getColumns: function(){},
            getCell: function(columnIndex, rowIndex) {
                var row;
                if (this._tableElement && this._tableElement.length === 1) {
                    row = this._tableElement[0].rows[rowIndex];
                    return row ? $(row.cells[columnIndex]) : null
                }
            },
            getRowsCount: function() {
                if (this._tableElement && this._tableElement.length === 1)
                    return this._tableElement[0].rows.length;
                return 0
            },
            getBoundingRect: function(){},
            getName: function(){}
        });
        $.extend(dataGrid.__internals, {
            DATAGRID_SORT_CLASS: DATAGRID_SORT_CLASS,
            DATAGRID_SORTUP_CLASS: DATAGRID_SORTUP_CLASS,
            DATAGRID_SORTDOWN_CLASS: DATAGRID_SORTDOWN_CLASS,
            DATAGRID_CELL_CONTENT_CLASS: DATAGRID_CELL_CONTENT_CLASS,
            DATAGRID_ROW_CLASS: DATAGRID_ROW_CLASS,
            DATAGRID_GROUP_ROW_CLASS: DATAGRID_GROUP_ROW_CLASS,
            DATAGRID_TABLE_CLASS: DATAGRID_TABLE_CLASS
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.columnHeadersView.js */
    (function($, DX) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var DATAGRID_CELL_CONTENT_CLASS = "dx-datagrid-text-content",
            DATAGRID_HEADERS_ACTION_CLASS = "dx-datagrid-action-cursor",
            DATAGRID_HEADERS_CONTAINER_CLASS = "dx-datagrid-headers-container",
            DATAGRID_HEADERS_CLASS = "dx-datagrid-headers",
            DATAGRID_HEADER_ROW_CLASS = "dx-header-row",
            DATAGRID_NOWRAP_CLASS = "dx-datagrid-nowrap",
            DATAGRID_GROUP_SPACE_CLASS = "dx-datagrid-group-space",
            DATAGRID_CONTENT_CLASS = "dx-datagrid-content",
            DATAGRID_COLUMN_LINES_CLASS = "dx-column-lines",
            DATAGRID_CONTEXT_MENU_SORT_ASC_ICON = "context-menu-sort-asc",
            DATAGRID_CONTEXT_MENU_SORT_DESC_ICON = "context-menu-sort-desc",
            DATAGRID_CONTEXT_MENU_SORT_NONE_ICON = "context-menu-sort-none",
            COLUMN_HEADERS_VIEW_NAMESPACE = 'dxDataGridColumnHeadersView';
        dataGrid.ColumnHeadersView = dataGrid.ColumnsView.inherit({
            _renderHeaderContent: function($cell, column, columnIndex) {
                var that = this,
                    $group = $('<div />'),
                    headerCellTemplate = column.headerCellTemplate;
                if (column.command === "empty" || column.command === "edit")
                    $cell.html('&nbsp;');
                else if (!utils.isDefined(column.groupIndex)) {
                    that._applySorting($cell, column);
                    var $content = $('<div />').addClass(DATAGRID_CELL_CONTENT_CLASS).appendTo($cell);
                    var templateOptions = {
                            column: column,
                            columnIndex: columnIndex
                        };
                    if ($.isFunction(headerCellTemplate))
                        headerCellTemplate($content, templateOptions);
                    else if (utils.isString(headerCellTemplate)) {
                        headerCellTemplate = that.getTemplate(headerCellTemplate);
                        if (headerCellTemplate)
                            headerCellTemplate.render($content, templateOptions)
                    }
                    else
                        $content.text(column.caption)
                }
                else
                    $cell.addClass(DATAGRID_GROUP_SPACE_CLASS)
            },
            _renderHeader: function(rootElement, column, columnIndex) {
                var that = this,
                    sorting = that.option('sorting'),
                    sortingMode = sorting && sorting.mode,
                    cellElement;
                cellElement = $('<td />').css('text-align', column.alignment).toggleClass(column.cssClass, !utils.isDefined(column.groupIndex));
                that._renderHeaderContent(cellElement, column, columnIndex);
                if (((sortingMode === 'single' || sortingMode === 'multiple') && column.allowSorting || column.allowReordering || column.allowHiding) && !utils.isDefined(column.groupIndex))
                    cellElement.addClass(DATAGRID_HEADERS_ACTION_CLASS);
                cellElement.appendTo(rootElement)
            },
            _renderCore: function() {
                var that = this,
                    $container = that._element(),
                    columns = that._columnsController.getVisibleColumns(),
                    scrollLeft = that._scrollLeft,
                    columnsLength = columns.length,
                    i,
                    $row;
                that._tableElement = that._createTable().attr('style', '-webkit-user-select: none').append(dataGrid.createColGroup(columns));
                if (that.option('showColumnHeaders')) {
                    $row = that._createRow().addClass(DATAGRID_HEADER_ROW_CLASS).toggleClass(DATAGRID_COLUMN_LINES_CLASS, that.option('showColumnLines'));
                    $row.on(events.addNamespace("dxclick", COLUMN_HEADERS_VIEW_NAMESPACE), 'td', that.createAction(function(e) {
                        var keyName = null,
                            event = e.jQueryEvent;
                        event.stopPropagation();
                        setTimeout(function() {
                            var column = columns[event.currentTarget.cellIndex];
                            if (event.shiftKey)
                                keyName = "shift";
                            else if (event.ctrlKey)
                                keyName = "ctrl";
                            if (column && !utils.isDefined(column.groupIndex))
                                that._columnsController.changeSortOrder(column.index, keyName)
                        })
                    }));
                    for (i = 0; i < columnsLength; i++)
                        that._renderHeader($row, columns[i], i);
                    that._tableElement.append($row)
                }
                $container.addClass(DATAGRID_HEADERS_CLASS).addClass(DATAGRID_CONTENT_CLASS).toggleClass(DATAGRID_NOWRAP_CLASS, !!that.option("columnAutoWidth") || !that.option("wordWrapEnabled")).empty();
                $('<div/>').addClass(DATAGRID_HEADERS_CONTAINER_CLASS).append(that._tableElement).appendTo($container);
                that._scrollLeft = 0;
                that.setScrollOffset(scrollLeft)
            },
            _afterRender: function($root) {
                var that = this;
                if (!$root)
                    that.setColumnWidths(that._columnWidths && that._columnWidths.length === that._columnsController.getVisibleColumns().length ? that._columnWidths : null);
                that._updateSortIndicatorPositions(that._element());
                that.processSizeChanged()
            },
            _updateSortIndicators: function() {
                var that = this,
                    columns = that._columnsController.getVisibleColumns(),
                    $element = that._element(),
                    $cells = $element.find('.' + DATAGRID_HEADER_ROW_CLASS + ' > td'),
                    i;
                for (i = 0; i < columns.length; i++)
                    if (!utils.isDefined(columns[i].groupIndex))
                        that._applySorting($cells.eq(i), columns[i]);
                that._updateSortIndicatorPositions($element)
            },
            _processColumnsChanged: function(e) {
                var visibleColumnIndex;
                if (e.changeType === 'sorting') {
                    this._updateSortIndicators();
                    return
                }
                switch (e.optionName) {
                    case'width':
                        visibleColumnIndex = this._columnsController.getVisibleIndex(e.columnIndex);
                        if (visibleColumnIndex !== -1) {
                            $(this._tableElement.find('col')[visibleColumnIndex]).css('width', e.column.width);
                            this._updateSortIndicatorPositions(this._element())
                        }
                        if (this._columnWidths)
                            this._columnWidths[visibleColumnIndex] = e.column.width;
                        break;
                    default:
                        this.render()
                }
            },
            _isElementVisible: function(elementOptions) {
                return elementOptions && elementOptions.visible
            },
            processSizeChanged: function() {
                var that = this,
                    $element = that._element();
                if (!utils.isDefined(that._headersHeight) || that._headersHeight !== $element.height()) {
                    that._headersHeight = $element.height();
                    that.sizeChanged.fire()
                }
            },
            getHeaderElement: function(index) {
                var columnElements = this.getColumnElements();
                return columnElements && columnElements.eq(index)
            },
            getColumnElements: function() {
                var that = this,
                    columnElements;
                if (that._tableElement) {
                    columnElements = that._tableElement.find('.' + DATAGRID_HEADER_ROW_CLASS).find('td');
                    if (columnElements.length)
                        return columnElements
                }
                return null
            },
            allowDragging: function(column, draggingPanels) {
                var i,
                    result = false,
                    columns = this.getColumns(),
                    draggableColumnCount = 0,
                    allowDrag = function(column) {
                        return column.allowReordering || column.allowGrouping || column.allowHiding
                    };
                for (i = 0; i < columns.length; i++)
                    if (allowDrag(columns[i]))
                        draggableColumnCount++;
                if (draggableColumnCount <= 1)
                    return false;
                else if (!draggingPanels)
                    return (this.option("allowColumnReordering") || this._columnsController.isColumnOptionUsed("allowReordering")) && column && column.allowReordering;
                for (i = 0; i < draggingPanels.length; i++)
                    if (draggingPanels[i].allowDragging(column))
                        return true;
                return false
            },
            getColumns: function() {
                return this._columnsController.getVisibleColumns()
            },
            getBoundingRect: function() {
                var that = this,
                    offset;
                if (that._tableElement.length > 0 && that._tableElement[0].rows.length > 0 && that._tableElement[0].rows[0].cells.length > 0) {
                    offset = that._tableElement.offset();
                    return {top: offset.top}
                }
                return null
            },
            getName: function() {
                return 'headers'
            },
            getHeadersLength: function() {
                var that = this;
                if (that._tableElement.length > 0 && that._tableElement[0].rows.length > 0)
                    return that._tableElement[0].rows[0].cells.length;
                return 0
            },
            tableElement: function() {
                return this._tableElement
            },
            init: function() {
                var that = this;
                that.callBase();
                that._dataController = that.getController('data');
                that._columnsController.columnsChanged.add(function(e) {
                    that._processColumnsChanged(e)
                });
                that._scrollerWidth = 0;
                that.sizeChanged = $.Callbacks()
            },
            isVisible: function() {
                return this.option('showColumnHeaders')
            },
            setScrollOffset: function(pos) {
                var that = this,
                    $element = that._element();
                if (that._scrollLeft !== pos) {
                    that._scrollLeft = pos;
                    $element && $element.find('.' + DATAGRID_HEADERS_CONTAINER_CLASS).scrollLeft(pos)
                }
            },
            setScrollerSpacing: function(width) {
                var that = this,
                    $element = that._element(),
                    rtlEnabled = that.option("rtlEnabled");
                that._scrollerWidth = width;
                $element && $element.css(rtlEnabled ? {paddingLeft: width} : {paddingRight: width})
            },
            optionChanged: function(name, value, prevValue) {
                var that = this;
                switch (name) {
                    case'showColumnHeaders':
                    case'wordWrapEnabled':
                    case'showColumnLines':
                        that.render();
                        break
                }
            },
            resize: function() {
                this.callBase();
                this._updateSortIndicatorPositions(this._element())
            },
            getHeight: function() {
                var that = this,
                    $element = that._element();
                return $element ? $element.height() : 0
            },
            getContextMenuItems: function($targetElement) {
                var that = this,
                    $cell,
                    column,
                    itemClickAction,
                    sortingOptions;
                if ($targetElement.closest("." + DATAGRID_HEADER_ROW_CLASS).length) {
                    $cell = $targetElement.closest("td");
                    column = $cell.length && that.getColumns()[$cell[0].cellIndex];
                    sortingOptions = that.option("sorting");
                    if (sortingOptions && sortingOptions.mode !== "none" && column && column.allowSorting) {
                        itemClickAction = function(params) {
                            setTimeout(function() {
                                that._columnsController.changeSortOrder(column.index, params.itemData.value)
                            })
                        };
                        return [{
                                    text: sortingOptions.ascendingText,
                                    value: "asc",
                                    icon: DATAGRID_CONTEXT_MENU_SORT_ASC_ICON,
                                    itemClickAction: itemClickAction
                                }, {
                                    text: sortingOptions.descendingText,
                                    value: "desc",
                                    icon: DATAGRID_CONTEXT_MENU_SORT_DESC_ICON,
                                    itemClickAction: itemClickAction
                                }, {
                                    text: sortingOptions.clearText,
                                    value: "none",
                                    icon: DATAGRID_CONTEXT_MENU_SORT_NONE_ICON,
                                    itemClickAction: itemClickAction
                                }]
                    }
                }
                return []
            }
        });
        $.extend(dataGrid.__internals, {
            DATAGRID_CELL_CONTENT_CLASS: DATAGRID_CELL_CONTENT_CLASS,
            DATAGRID_HEADERS_ACTION_CLASS: DATAGRID_HEADERS_ACTION_CLASS,
            DATAGRID_HEADERS_CONTAINER_CLASS: DATAGRID_HEADERS_CONTAINER_CLASS,
            DATAGRID_HEADERS_CLASS: DATAGRID_HEADERS_CLASS,
            DATAGRID_NOWRAP_CLASS: DATAGRID_NOWRAP_CLASS
        });
        dataGrid.registerModule('columnHeaders', {
            defaultOptions: function() {
                return {showColumnHeaders: true}
            },
            views: {columnHeadersView: dataGrid.ColumnHeadersView}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.filterRow.js */
    (function($, DX) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var OPERATION_ICONS = {
                '=': 'filter-operation-equals',
                '<>': 'filter-operation-not-equals',
                '<': 'filter-operation-less',
                '<=': 'filter-operation-less-equal',
                '>': 'filter-operation-greater',
                '>=': 'filter-operation-greater-equal',
                'default': 'filter-operation-default',
                notcontains: 'filter-operation-not-contains',
                contains: 'filter-operation-contains',
                startswith: 'filter-operation-starts-with',
                endswith: 'filter-operation-ends-with'
            };
        var DATAGRID_FILTER_ROW_CLASS = "dx-datagrid-filter-row",
            DATAGRID_MENU_CLASS = "dx-menu",
            DATAGRID_MENU_IMAGE_CLASS = 'dx-menu-image',
            DATAGRID_CELL_CONTENT_CLASS = "dx-datagrid-text-content",
            DATAGRID_GROUP_SPACE_CLASS = "dx-datagrid-group-space",
            DATAGRID_EDITOR_WITH_MENU_CLASS = "dx-editor-with-menu",
            DATAGRID_EDITOR_CONTAINER_CLASS = "dx-editor-container",
            DATAGRID_COLUMN_LINES_CLASS = "dx-column-lines",
            DATAGRID_EDITOR_CELL_CLASS = "dx-editor-cell";
        var ColumnHeadersViewFilterRowExtender = {
                _processColumnsChanged: function(e) {
                    var that = this,
                        visibleIndex,
                        textBox,
                        $menu;
                    if (e.optionName === 'filterText')
                        return;
                    if (e.optionName === 'selectedFilterOperation' || e.optionName && e.optionName.selectedFilterOperation) {
                        visibleIndex = that.getController('columns').getVisibleIndex(e.columnIndex);
                        if (visibleIndex >= 0) {
                            $menu = that._element().find('.' + DATAGRID_FILTER_ROW_CLASS).children().eq(visibleIndex).find('.' + DATAGRID_MENU_CLASS);
                            if ($menu.length) {
                                that._updateFilterOperationChooser($menu, e.column);
                                textBox = $menu.prev().children().data('dxTextBox');
                                if (textBox)
                                    textBox.option('value', e.column.filterText)
                            }
                        }
                    }
                    else
                        that.callBase(e)
                },
                isFilterRowVisible: function() {
                    return this._isElementVisible(this.option('filterRow'))
                },
                isVisible: function() {
                    return this.callBase() || this.isFilterRowVisible()
                },
                _renderCore: function() {
                    this.callBase();
                    var that = this,
                        columns = that._columnsController.getVisibleColumns(),
                        i,
                        rowElement;
                    if (that.isFilterRowVisible()) {
                        rowElement = that._createRow().appendTo(that._tableElement);
                        rowElement.addClass(DATAGRID_FILTER_ROW_CLASS).toggleClass(DATAGRID_COLUMN_LINES_CLASS, that.option('showColumnLines'));
                        for (i = 0; i < columns.length; i++)
                            that._renderFilterRowCell(rowElement, columns[i])
                    }
                },
                _updateFilterOperationChooser: function($menu, column) {
                    var that = this;
                    $menu.dxMenu({
                        highlightActiveItem: true,
                        cssClass: 'dx-datagrid dx-widget',
                        showPopupMode: 'onhover',
                        items: [{
                                disabled: column.filterOperations && column.filterOperations.length ? false : true,
                                icon: OPERATION_ICONS[column.selectedFilterOperation || "default"],
                                items: that._getFilterOperationMenuItems(column)
                            }],
                        itemClickAction: function(properties) {
                            var selectedFilterOperation = properties.itemData.name;
                            if (properties.itemData.items)
                                return;
                            if (selectedFilterOperation)
                                that._columnsController.columnOption(column.initialIndex, 'selectedFilterOperation', selectedFilterOperation);
                            else
                                that._columnsController.columnOption(column.initialIndex, {
                                    selectedFilterOperation: null,
                                    filterText: null
                                })
                        },
                        rtlEnabled: that.option('rtlEnabled')
                    })
                },
                _renderFilterOperationChooser: function($container, column) {
                    var that = this,
                        $menu;
                    if (that.option("filterRow.showOperationChooser")) {
                        $container.addClass(DATAGRID_EDITOR_WITH_MENU_CLASS);
                        $menu = $('<div />').appendTo($container);
                        that._updateFilterOperationChooser($menu, column)
                    }
                },
                _getFilterOperationMenuItems: function(column) {
                    var that = this,
                        result = [{}],
                        filterRowOptions = that.option("filterRow"),
                        operationDescriptions = filterRowOptions && filterRowOptions.operationDescriptions || {};
                    if (column.filterOperations && column.filterOperations.length) {
                        result = $.map(column.filterOperations, function(value) {
                            return {
                                    name: value,
                                    selectable: true,
                                    selected: column.selectedFilterOperation ? column.selectedFilterOperation === value : column.filterOperations[0] === value,
                                    text: operationDescriptions[value],
                                    icon: OPERATION_ICONS[value]
                                }
                        });
                        result.push({
                            name: null,
                            text: filterRowOptions && filterRowOptions.resetOperationText,
                            allowSelectOnclick: false,
                            icon: OPERATION_ICONS['default']
                        })
                    }
                    return result
                },
                _renderFilterRowCell: function(rootElement, column) {
                    var that = this,
                        $cell = $('<td />').toggleClass(column.cssClass, !utils.isDefined(column.groupIndex)).appendTo(rootElement),
                        $container,
                        $editorContainer,
                        $editor;
                    var updateFilterText = function(that, column, value) {
                            var filterOptions,
                                filterText = column.dataType === "date" ? DX.formatHelper.format(value, column.format) : value,
                                columnsController = that._columnsController;
                            if (!column.filterText && !filterText)
                                return;
                            column.filterText = filterText;
                            columnsController.columnOption(column.initialIndex, 'filterText', filterText)
                        };
                    if (column.command === 'empty')
                        $cell.html('&nbsp;');
                    else if (utils.isDefined(column.groupIndex))
                        $cell.addClass(DATAGRID_GROUP_SPACE_CLASS);
                    else if (column.allowFiltering) {
                        $cell.addClass(DATAGRID_EDITOR_CELL_CLASS);
                        $container = $('<div />').appendTo($cell),
                        $editorContainer = $('<div />').addClass(DATAGRID_EDITOR_CONTAINER_CLASS).appendTo($container),
                        $editor = $('<div />').appendTo($editorContainer);
                        that.getController('editorFactory').createEditor($editor, $.extend({}, column, {
                            value: function(value) {
                                if (value === undefined)
                                    return column.parseValue ? column.parseValue(column.filterText) : column.filterText;
                                else
                                    updateFilterText(that, column, value)
                            },
                            filtering: true,
                            showAllText: that.option('filterRow.showAllText'),
                            width: null
                        }));
                        if (column.alignment)
                            $cell.find('input').first().css('text-align', column.alignment);
                        if (column.filterOperations && column.filterOperations.length)
                            that._renderFilterOperationChooser($container, column)
                    }
                },
                optionChanged: function(name, value, prevValue) {
                    var that = this;
                    switch (name) {
                        case'filterRow':
                        case'showColumnLines':
                        case'disabled':
                            that.render();
                            break;
                        default:
                            that.callBase(name);
                            break
                    }
                }
            };
        var processFilterExpession = function(text) {
                var operation,
                    i,
                    compareOperations = ['>=', '<=', '<>', '=', '>', '<'];
                if (!text)
                    return null;
                for (i = 0; i < compareOperations.length; i++)
                    if (text.indexOf && text.indexOf(compareOperations[i]) === 0) {
                        operation = compareOperations[i];
                        text = text.substr(operation.length);
                        break
                    }
                if (!text)
                    return null;
                else
                    return {
                            value: text,
                            operation: operation
                        }
            };
        dataGrid.processFilterExpession = processFilterExpession;
        var DataControllerFilterRowExtender = {_calculateAdditionalFilter: function() {
                    var that = this,
                        filter = that.callBase(),
                        i,
                        filters = [],
                        resultFilter = [],
                        columns = that._columnsController.getVisibleColumns();
                    $.each(columns, function() {
                        var filterOptions,
                            filter;
                        if (this.allowFiltering && this.calculateFilterExpression && this.filterText) {
                            if (this.selectedFilterOperation)
                                filter = this.calculateFilterExpression(this.filterText, this.selectedFilterOperation);
                            else {
                                filterOptions = processFilterExpession(this.filterText);
                                if (filterOptions)
                                    filter = this.calculateFilterExpression(filterOptions.value, filterOptions.operation)
                            }
                            if (filter)
                                filters.push(filter)
                        }
                    });
                    if (filters.length) {
                        if (filter && filter.length)
                            filters.unshift(filter);
                        for (i = 0; i < filters.length; i++) {
                            if (i > 0)
                                resultFilter.push('and');
                            resultFilter.push(filters[i])
                        }
                    }
                    else
                        resultFilter = filter;
                    return resultFilter && resultFilter.length ? resultFilter : null
                }};
        var ColumnsControllerFilterRowExtender = {_createCalculatedColumnOptions: function(columnOptions) {
                    var calculatedColumnOptions = this.callBase(columnOptions);
                    if (columnOptions.dataField) {
                        $.extend(calculatedColumnOptions, {
                            calculateFilterExpression: function(text, selectedFilterOperation) {
                                var column = this,
                                    dataField = column.dataField,
                                    filter = null,
                                    parsedValue = column.parseValue(text);
                                if (parsedValue !== undefined)
                                    if (column.dataType === 'string')
                                        filter = [dataField, selectedFilterOperation || 'contains', parsedValue];
                                    else if (column.dataType === 'date') {
                                        var dateStart = new Date(parsedValue.getFullYear(), parsedValue.getMonth(), parsedValue.getDate()),
                                            dateEnd = new Date(parsedValue.getFullYear(), parsedValue.getMonth(), parsedValue.getDate() + 1);
                                        switch (selectedFilterOperation) {
                                            case'<':
                                                return [dataField, '<', dateStart];
                                            case'<=':
                                                return [dataField, '<', dateEnd];
                                            case'>':
                                                return [dataField, '>=', dateEnd];
                                            case'>=':
                                                return [dataField, '>=', dateStart];
                                            case'<>':
                                                return [[dataField, '<', dateStart], 'or', [dataField, '>=', dateEnd]];
                                            default:
                                                return [[dataField, '>=', dateStart], 'and', [dataField, '<', dateEnd]]
                                        }
                                    }
                                    else
                                        filter = [dataField, selectedFilterOperation || '=', parsedValue];
                                return filter
                            },
                            allowFiltering: true
                        });
                        if (columnOptions.displayMap)
                            $.extend(calculatedColumnOptions, {
                                dataType: 'string',
                                customizeText: function(options) {
                                    var value = options.value,
                                        displayText = value !== undefined ? columnOptions.displayMap[value] : undefined;
                                    return displayText !== undefined ? displayText : columnOptions.displayMap['default']
                                },
                                calculateFilterExpression: function(text, selectedFilterOperation) {
                                    var key,
                                        value;
                                    for (key in this.displayMap) {
                                        value = this.displayMap[key];
                                        if (key !== 'default' && value && (selectedFilterOperation ? value === text : value.indexOf && value.indexOf(text) !== -1)) {
                                            if (utils.isNumber(key))
                                                key = new Number(key);
                                            return [this.dataField, selectedFilterOperation || '=', key]
                                        }
                                    }
                                    return null
                                }
                            })
                    }
                    else
                        $.extend(calculatedColumnOptions, {allowFiltering: !!columnOptions.calculateFilterExpression});
                    return calculatedColumnOptions
                }};
        dataGrid.registerModule('filterRow', {
            defaultOptions: function() {
                return {filterRow: {
                            visible: false,
                            showOperationChooser: true,
                            showAllText: Globalize.localize("dxDataGrid-filterRowShowAllText"),
                            resetOperationText: Globalize.localize("dxDataGrid-filterRowResetOperationText"),
                            operationDescriptions: {
                                '=': Globalize.localize("dxDataGrid-filterRowOperationEquals"),
                                '<>': Globalize.localize("dxDataGrid-filterRowOperationNotEquals"),
                                '<': Globalize.localize("dxDataGrid-filterRowOperationLess"),
                                '<=': Globalize.localize("dxDataGrid-filterRowOperationLessOrEquals"),
                                '>': Globalize.localize("dxDataGrid-filterRowOperationGreater"),
                                '>=': Globalize.localize("dxDataGrid-filterRowOperationGreaterOrEquals"),
                                startswith: Globalize.localize("dxDataGrid-filterRowOperationStartsWith"),
                                contains: Globalize.localize("dxDataGrid-filterRowOperationContains"),
                                notcontains: Globalize.localize("dxDataGrid-filterRowOperationNotContains"),
                                endswith: Globalize.localize("dxDataGrid-filterRowOperationEndsWith")
                            }
                        }}
            },
            extenders: {
                controllers: {
                    data: DataControllerFilterRowExtender,
                    columns: ColumnsControllerFilterRowExtender
                },
                views: {columnHeadersView: ColumnHeadersViewFilterRowExtender}
            }
        });
        $.extend(dataGrid.__internals, {
            DATAGRID_FILTER_ROW_CLASS: DATAGRID_FILTER_ROW_CLASS,
            DATAGRID_MENU_CLASS: DATAGRID_MENU_CLASS,
            DATAGRID_MENU_IMAGE_CLASS: DATAGRID_MENU_IMAGE_CLASS,
            DATAGRID_CELL_CONTENT_CLASS: DATAGRID_CELL_CONTENT_CLASS,
            DATAGRID_EDITOR_WITH_MENU_CLASS: DATAGRID_EDITOR_WITH_MENU_CLASS,
            DATAGRID_EDITOR_CONTAINER_CLASS: DATAGRID_EDITOR_CONTAINER_CLASS
        });
        dataGrid.ColumnHeadersViewFilterRowExtender = ColumnHeadersViewFilterRowExtender;
        dataGrid.DataControllerFilterRowExtender = DataControllerFilterRowExtender
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.headerPanel.js */
    (function($, DX) {
        var ui = DX.ui,
            events = ui.events,
            dataGrid = ui.dataGrid;
        var DATAGRID_HEADER_PANEL_CLASS = "dx-datagrid-header-panel",
            DATAGRID_GROUP_PANEL_CLASS = "dx-datagrid-group-panel",
            DATAGRID_GROUP_PANEL_MESSAGE_CLASS = "dx-group-panel-message",
            DATAGRID_GROUP_PANEL_ITEM_CLASS = "dx-group-panel-item",
            DATAGRID_HEADERS_ACTION_CLASS = "dx-datagrid-action-cursor";
        dataGrid.HeaderPanel = dataGrid.ColumnsView.inherit({
            _renderGroupPanel: function() {
                var that = this,
                    $element = that._element(),
                    groupPanelOptions = that.option("groupPanel"),
                    $groupPanel,
                    groupColumns = that.getController('columns').getVisibleGroupColumns();
                $groupPanel = $element.find('.' + DATAGRID_GROUP_PANEL_CLASS);
                if (groupPanelOptions && groupPanelOptions.visible) {
                    if (!$groupPanel.length)
                        $groupPanel = $('<div />').addClass(DATAGRID_GROUP_PANEL_CLASS).prependTo($element);
                    else
                        $groupPanel.show();
                    that._renderGroupPanelItems($groupPanel, groupColumns);
                    if (!groupColumns.length)
                        $('<div />').addClass(DATAGRID_GROUP_PANEL_MESSAGE_CLASS).text(groupPanelOptions.emptyPanelText).appendTo($groupPanel)
                }
                else
                    $groupPanel.hide()
            },
            _renderGroupPanelItems: function($groupPanel, groupColumns) {
                var that = this,
                    $item;
                $groupPanel.empty();
                $.each(groupColumns, function(index, groupColumn) {
                    $item = $('<div />').addClass(groupColumn.cssClass).addClass(DATAGRID_GROUP_PANEL_ITEM_CLASS).toggleClass(DATAGRID_HEADERS_ACTION_CLASS, groupColumn.allowSorting || groupColumn.allowReordering).appendTo($groupPanel).text(groupColumn.caption).on(events.addNamespace("dxclick", "dxDataGridHeaderPanel"), that.createAction(function(e) {
                        setTimeout(function() {
                            that.getController('columns').changeSortOrder(groupColumn.index)
                        })
                    }));
                    that._applySorting($item, {
                        alignment: 'left',
                        sortOrder: groupColumn.sortOrder === 'desc' ? 'desc' : 'asc'
                    })
                });
                that._updateSortIndicatorPositions($groupPanel)
            },
            _renderCore: function() {
                var that = this;
                that._element().addClass(DATAGRID_HEADER_PANEL_CLASS);
                that._renderGroupPanel()
            },
            getHeaderPanel: function() {
                return this._element()
            },
            allowDragging: function(column) {
                var groupPanelOptions = this.option("groupPanel");
                return groupPanelOptions && groupPanelOptions.visible && groupPanelOptions.allowColumnDragging && column && column.allowGrouping
            },
            getColumnElements: function() {
                var $element = this._element();
                return $element && $element.find('.' + DATAGRID_GROUP_PANEL_ITEM_CLASS)
            },
            getColumns: function() {
                return this.getController('columns').getVisibleGroupColumns()
            },
            getBoundingRect: function() {
                var that = this,
                    $element = that._element(),
                    offset;
                if ($element && $element.find('.' + DATAGRID_GROUP_PANEL_CLASS).length) {
                    offset = $element.offset();
                    return {
                            top: offset.top,
                            bottom: offset.top + $element.height()
                        }
                }
                return null
            },
            getName: function() {
                return 'group'
            },
            init: function() {
                var that = this;
                that.callBase();
                that.getController('columns').columnsChanged.add(function(e) {
                    if (e.optionName !== 'width')
                        that.render()
                })
            },
            isVisible: function() {
                var groupPanelOptions = this.option('groupPanel');
                return groupPanelOptions && groupPanelOptions.visible
            },
            getHeight: function() {
                var $element = this._element();
                return $element ? $element.outerHeight(true) : 0
            },
            optionChanged: function(name, value, prevValue) {
                var that = this;
                switch (name) {
                    case'searchPanel':
                        that._renderSearchPanel();
                        break;
                    case'groupPanel':
                        that._renderGroupPanel();
                        break;
                    case'disabled':
                        that.render();
                        break
                }
            },
            resize: function() {
                var that = this,
                    $element = that._element(),
                    $groupPanel = $element && $element.find('.' + DATAGRID_GROUP_PANEL_CLASS),
                    groupPanelOptions = that.option('groupPanel');
                that.callBase();
                that._updateSortIndicatorPositions($groupPanel)
            }
        });
        $.extend(dataGrid.__internals, {
            DATAGRID_HEADER_PANEL_CLASS: DATAGRID_HEADER_PANEL_CLASS,
            DATAGRID_GROUP_PANEL_CLASS: DATAGRID_GROUP_PANEL_CLASS,
            DATAGRID_GROUP_PANEL_MESSAGE_CLASS: DATAGRID_GROUP_PANEL_MESSAGE_CLASS,
            DATAGRID_GROUP_PANEL_ITEM_CLASS: DATAGRID_GROUP_PANEL_ITEM_CLASS,
            DATAGRID_HEADERS_ACTION_CLASS: DATAGRID_HEADERS_ACTION_CLASS
        });
        dataGrid.registerModule('headerPanel', {
            defaultOptions: function() {
                return {groupPanel: {
                            visible: false,
                            emptyPanelText: Globalize.localize("dxDataGrid-groupPanelEmptyText"),
                            allowColumnDragging: true
                        }}
            },
            views: {headerPanel: dataGrid.HeaderPanel}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.search.js */
    (function($, DX) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var DATAGRID_SEARCH_PANEL_CLASS = "dx-datagrid-search-panel",
            MARGIN_RIGHT = 10;
        dataGrid.registerModule('search', {
            defaultOptions: function() {
                return {searchPanel: {
                            visible: false,
                            width: 160,
                            placeholder: Globalize.localize("dxDataGrid-searchPanelPlaceholder"),
                            highlightSearchText: true
                        }}
            },
            extenders: {
                controllers: {data: function() {
                        var calculateSearchFilter = function(that, text) {
                                var i,
                                    column,
                                    columns = that._columnsController.getColumns(),
                                    filter,
                                    searchFilter = [];
                                if (!text)
                                    return null;
                                for (i = 0; i < columns.length; i++) {
                                    column = columns[i];
                                    if (column.allowFiltering && column.calculateFilterExpression) {
                                        filter = column.calculateFilterExpression(text);
                                        if (filter) {
                                            if (searchFilter.length > 0)
                                                searchFilter.push('or');
                                            searchFilter.push(filter)
                                        }
                                    }
                                }
                                return searchFilter
                            };
                        return {
                                publicMethods: function() {
                                    return this.callBase().concat(['searchByText'])
                                },
                                _calculateAdditionalFilter: function() {
                                    var that = this,
                                        filter = that.callBase(),
                                        searchFilter = calculateSearchFilter(that, that._searchText);
                                    if (searchFilter)
                                        if (filter)
                                            filter = [filter, 'and', searchFilter];
                                        else
                                            filter = searchFilter;
                                    return filter
                                },
                                searchByText: function(text) {
                                    var that = this;
                                    if (that._searchText !== text) {
                                        that._searchText = text;
                                        that._applyFilter()
                                    }
                                },
                                getSearchText: function() {
                                    return this._searchText || ''
                                }
                            }
                    }()},
                views: {headerPanel: function() {
                        var getSearchPanelOptions = function(that) {
                                return that.option('searchPanel')
                            };
                        return {
                                _renderSearchPanel: function() {
                                    var that = this,
                                        $element = that._element(),
                                        dataController = that.getController('data'),
                                        searchPanelOptions = getSearchPanelOptions(that);
                                    if (searchPanelOptions && searchPanelOptions.visible) {
                                        if (!that._$searchPanel)
                                            that._$searchPanel = $('<div/>').addClass(DATAGRID_SEARCH_PANEL_CLASS).prependTo($element);
                                        else
                                            that._$searchPanel.show();
                                        that.getController('editorFactory').createEditor(that._$searchPanel, {
                                            width: searchPanelOptions.width,
                                            placeholder: searchPanelOptions.placeholder,
                                            filtering: true,
                                            searching: true,
                                            value: function(value) {
                                                if (value === undefined)
                                                    return dataController.getSearchText();
                                                else
                                                    dataController.searchByText(value)
                                            }
                                        });
                                        that.resize()
                                    }
                                    else
                                        that._$searchPanel && that._$searchPanel.hide()
                                },
                                _renderCore: function() {
                                    this.callBase();
                                    this._renderSearchPanel()
                                },
                                focus: function() {
                                    var textBox = this._$searchPanel.dxTextBox("instance");
                                    if (textBox)
                                        textBox.focus()
                                },
                                isVisible: function() {
                                    var searchPanelOptions = getSearchPanelOptions(this);
                                    return this.callBase() || searchPanelOptions && searchPanelOptions.visible
                                }
                            }
                    }()}
            }
        });
        dataGrid.__internals = $.extend({}, dataGrid.__internals, {DATAGRID_SEARCH_PANEL_CLASS: DATAGRID_SEARCH_PANEL_CLASS})
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.rowsView.js */
    (function($, DX) {
        var ui = DX.ui,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var DATAGRID_CELL_CONTENT_CLASS = "dx-datagrid-text-content",
            DATAGRID_GROUP_ROW_CLASS = "dx-group-row",
            DATAGRID_SEARCH_TEXT_CLASS = "dx-datagrid-search-text",
            DATAGRID_ROWS_VIEW_CLASS = "dx-datagrid-rowsview",
            DATAGRID_TABLE_CONTENT_CLASS = "dx-datagrid-table-content",
            DATAGRID_TABLE_CLASS = "dx-datagrid-table",
            DATAGRID_ROW_CLASS = "dx-row",
            DATAGRID_DATA_ROW_CLASS = "dx-data-row",
            DATAGRID_FREESPACE_CLASS = "dx-freespace-row",
            DATAGRID_BOTTOM_LOAD_PANEL_CLASS = "dx-datagrid-bottom-load-panel",
            DATAGRID_NODATA_TEXT_CLASS = "dx-datagrid-nodata",
            DATAGRID_LAST_ROW = "dx-last-row",
            DATAGRID_GROUP_SPACE_CLASS = "dx-datagrid-group-space",
            DATAGRID_GROUP_OPENED_CLASS = "dx-datagrid-group-opened",
            DATAGRID_GROUP_CLOSED_CLASS = "dx-datagrid-group-closed",
            DATAGRID_ROW_HOVERED = "dx-datagrid-row-hovered",
            DATAGRID_CONTENT_CLASS = "dx-datagrid-content",
            DATAGRID_NOWRAP_CLASS = "dx-datagrid-nowrap",
            DATAGRID_ROW_LINES_CLASS = "dx-row-lines",
            DATAGRID_COLUMN_LINES_CLASS = "dx-column-lines",
            DATAGRID_ROW_ALTERNATION_CLASS = 'dx-row-alt',
            DATAGRID_EDITOR_CELL_CLASS = "dx-editor-cell",
            PIXELS_LIMIT = 250000;
        var formatValue = function(value, options) {
                var formatObject = {
                        value: value,
                        valueText: DX.formatHelper.format(value, options.format, options.precision) || ''
                    };
                return options.customizeText ? options.customizeText.call(options, formatObject) : formatObject.valueText
            };
        var appendElementTemplate = {render: function(container, element) {
                    container.append(element)
                }};
        var createScrollableOptions = function(that) {
                var useNativeScrolling = that.option("scrolling.useNativeScrolling");
                var options = {
                        direction: "both",
                        rtlEnabled: that.option("rtlEnabled") || DX.rtlEnabled,
                        disabled: that.option("disabled"),
                        bounceEnabled: false,
                        useKeyboard: false
                    };
                if (useNativeScrolling === undefined)
                    useNativeScrolling = true;
                if (useNativeScrolling !== 'auto') {
                    options.useNative = !!useNativeScrolling;
                    options.useSimulatedScrollbar = !useNativeScrolling
                }
                return options
            };
        dataGrid.createScrollableOptions = createScrollableOptions;
        dataGrid.RowsView = dataGrid.ColumnsView.inherit({
            _getDefaultTemplate: function(column) {
                var that = this;
                if (column.command === 'group')
                    return function(container, options) {
                            if (!utils.isDefined(options.value) || options.data && options.data.isContinuation)
                                container.addClass(DATAGRID_GROUP_SPACE_CLASS);
                            else
                                container.addClass(options.value ? DATAGRID_GROUP_OPENED_CLASS : DATAGRID_GROUP_CLOSED_CLASS).on('dxclick', that.createAction(function() {
                                    that._dataController.changeGroupExpand(options.values)
                                }))
                        };
                else if (column.command === 'empty')
                    return function(container) {
                            container.html('&nbsp;')
                        };
                else
                    return function(container, options) {
                            container.text(options.text)
                        }
            },
            _getDefaultGroupTemplate: function() {
                var scrollingMode = this.option('scrolling.mode'),
                    grouping = this.option('grouping'),
                    align = this.option('rtlEnabled') ? 'right' : 'left';
                return function(container, options) {
                        var data = options.data,
                            text = options.column.caption + ": " + options.text;
                        if (scrollingMode !== 'virtual' && scrollingMode !== 'infinite' && data && grouping)
                            if (data.isContinuationOnNextPage && data.isContinuation)
                                text += ' (' + grouping.groupContinuedMessage + '. ' + grouping.groupContinuesMessage + ')';
                            else if (data.isContinuationOnNextPage)
                                text += ' (' + grouping.groupContinuesMessage + ')';
                            else if (data.isContinuation)
                                text += ' (' + grouping.groupContinuedMessage + ')';
                        container.css('text-align', align).text(text)
                    }
            },
            _update: function(change){},
            _createRow: function(rowOptions) {
                var $row = this.callBase(),
                    isGroup,
                    isDataRow;
                if (rowOptions) {
                    isGroup = rowOptions.rowType === 'group';
                    isDataRow = rowOptions.rowType === 'data';
                    $row.toggleClass(DATAGRID_DATA_ROW_CLASS, isDataRow).toggleClass(DATAGRID_ROW_ALTERNATION_CLASS, isDataRow && rowOptions.dataIndex % 2 === 1 && this.option('rowAlternationEnabled')).toggleClass(DATAGRID_ROW_LINES_CLASS, isDataRow && this.option('showRowLines')).toggleClass(DATAGRID_COLUMN_LINES_CLASS, this.option('showColumnLines')).toggleClass(DATAGRID_GROUP_ROW_CLASS, isGroup).toggleClass(DATAGRID_ROW_HOVERED, !!this.option("hoverStateEnabled") && !isGroup)
                }
                return $row
            },
            _highlightSearchText: function(cellElement, isEquals) {
                var that = this,
                    $parent,
                    searchHTML,
                    searchText = that._dataController.getSearchText();
                if (searchText && that.option("searchPanel.highlightSearchText")) {
                    searchHTML = $('<div>').text(searchText).html();
                    $parent = cellElement.parent();
                    if (!$parent.length)
                        $parent = $('<div>').append(cellElement);
                    $.each($parent.find(":dxicontains('" + searchText + "')"), function(index, element) {
                        $.each($(element).contents(), function(index, content) {
                            if (content.nodeType !== 3)
                                return;
                            var highlightSearchTextInTextNode = function($content, searchText) {
                                    var $searchTextSpan = $('<span />').addClass(DATAGRID_SEARCH_TEXT_CLASS),
                                        text = $content.text(),
                                        index = text.toLowerCase().indexOf(searchText.toLowerCase());
                                    if (index >= 0) {
                                        if ($content[0].textContent)
                                            $content[0].textContent = text.substr(0, index);
                                        else
                                            $content[0].nodeValue = text.substr(0, index);
                                        $content.after($searchTextSpan.text(text.substr(index, searchText.length)));
                                        $content = $(document.createTextNode(text.substr(index + searchText.length))).insertAfter($searchTextSpan);
                                        return highlightSearchTextInTextNode($content, searchText)
                                    }
                                };
                            if (isEquals) {
                                if ($(content).text().toLowerCase() === searchText.toLowerCase())
                                    $(this).replaceWith($('<span />').addClass(DATAGRID_SEARCH_TEXT_CLASS).text($(content).text()))
                            }
                            else
                                highlightSearchTextInTextNode($(content), searchText)
                        })
                    })
                }
            },
            _renderTemplate: function(container, template, options) {
                var that = this;
                if ($.isFunction(template))
                    template(container, options);
                else if (utils.isString(template)) {
                    if (!that._templatesCache[template])
                        that._templatesCache[template] = that.getTemplate(template);
                    template = that._templatesCache[template];
                    if (template)
                        if (template.allowRenderToDetachedContainer)
                            template.render(container, options);
                        else
                            that._delayedTemplates.push({
                                template: template,
                                container: container,
                                options: options
                            })
                }
            },
            _getColumnTemplate: function(options) {
                var that = this,
                    column = options.column,
                    template;
                if (column.groupIndex !== undefined)
                    template = column.groupCellTemplate || that._getDefaultGroupTemplate();
                else
                    template = column.cellTemplate || that._getDefaultTemplate(column);
                return template
            },
            _updateCell: function($cell, parameters) {
                var that = this,
                    column = parameters.column,
                    isEquals = column.dataType !== "string";
                if (column.allowFiltering)
                    that._highlightSearchText($cell, isEquals);
                if (parameters.rowType === "data" && column.groupIndex === undefined)
                    that._cellPrepared($cell, parameters)
            },
            _createCell: function(value, item, rowIndex, column, columnIndex) {
                var that = this,
                    template,
                    displayValue = column.lookup ? column.lookup.calculateCellValue(value) : value,
                    $cell = $('<td />').addClass(column.cssClass);
                var parameters = {
                        value: value,
                        displayValue: displayValue,
                        row: item,
                        key: item && item.key,
                        data: item && item.data,
                        rowType: item && item.rowType,
                        values: item && item.values,
                        text: formatValue(displayValue, column),
                        rowIndex: rowIndex,
                        columnIndex: columnIndex,
                        column: column,
                        resized: column.resizedCallbacks
                    };
                template = that._getColumnTemplate(parameters);
                that._renderTemplate($cell, template, parameters);
                that._updateCell($cell, parameters);
                return $cell
            },
            _cellPrepared: function($cell, options) {
                var that = this,
                    cellPrepared = that.option("cellPrepared"),
                    alignment = options.column.alignment,
                    extendOptions = function(event) {
                        return {
                                cellElement: $(event.target).closest('td'),
                                jQueryEvent: event,
                                eventType: event.type
                            }
                    };
                if (alignment)
                    $cell[0].style.textAlign = alignment;
                if (that.option("cellClick"))
                    $cell.on("dxclick", function(e) {
                        that.executeAction("cellClick", $.extend({}, options, extendOptions(e)))
                    });
                if (that.option("cellHoverChanged")) {
                    $cell.on("mouseover", function(e) {
                        that.executeAction("cellHoverChanged", $.extend({}, options, extendOptions(e)))
                    });
                    $cell.on("mouseout", function(e) {
                        that.executeAction("cellHoverChanged", $.extend({}, options, extendOptions(e)))
                    })
                }
                if (utils.isFunction(cellPrepared))
                    cellPrepared($cell, options)
            },
            _rowPrepared: function($row, options) {
                var that = this,
                    rowPrepared = that.option("rowPrepared");
                if (utils.isFunction(rowPrepared))
                    rowPrepared($row, options)
            },
            _renderScrollable: function($table) {
                var that = this,
                    loadPanelOptions,
                    disposing = that.disposing,
                    $element = that._element(),
                    scrollHandler,
                    dxScrollableOptions,
                    scrollingOptions = that.option("scrolling");
                if (!utils.isDefined(that._tableElement)) {
                    that._tableElement = $table;
                    if (!$element.children().length)
                        $element.append('<div />');
                    if ($element.dxLoadPanel) {
                        loadPanelOptions = that.option("loadPanel");
                        if (loadPanelOptions && loadPanelOptions.enabled) {
                            var loadPanelOptions = {
                                    shading: false,
                                    message: loadPanelOptions.text,
                                    width: loadPanelOptions.width,
                                    height: loadPanelOptions.height,
                                    animation: loadPanelOptions.animation,
                                    position: {of: $element},
                                    targetContainer: $element
                                };
                            if (that._loadPanel)
                                that._loadPanel.option(loadPanelOptions);
                            else
                                that._loadPanel = $('<div />').appendTo($element.parent()).dxLoadPanel(loadPanelOptions).dxLoadPanel('instance')
                        }
                        else {
                            that._loadPanel && that._loadPanel._element().remove();
                            that._loadPanel = null
                        }
                    }
                    scrollHandler = function(e) {
                        var $content = that._findContentElement();
                        if (that._hasHeight && that._rowHeight) {
                            that._scrollTop = e.scrollOffset.top;
                            that._dataController.setViewportItemIndex(that._scrollTop / that._rowHeight)
                        }
                        that.scrollOffsetChanged.fire(e.scrollOffset)
                    };
                    dxScrollableOptions = createScrollableOptions(that);
                    dxScrollableOptions.scrollAction = scrollHandler;
                    dxScrollableOptions.stopAction = scrollHandler;
                    $element.dxScrollable(dxScrollableOptions);
                    that._scrollable = $element.data('dxScrollable');
                    that._scrollableContainer = that._scrollable._$container;
                    if (!that._windowScrollHandler) {
                        that._windowScrollHandler = that.createAction(function() {
                            var contentOffset,
                                scrollTop;
                            if (!that._hasHeight && that._rowHeight) {
                                contentOffset = $element.offset().top;
                                scrollTop = $(window).scrollTop() - contentOffset;
                                scrollTop = scrollTop > 0 ? scrollTop : 0;
                                that._scrollTop = scrollTop;
                                that._dataController.setViewportItemIndex(scrollTop / that._rowHeight)
                            }
                        });
                        $(window).on('scroll', that._windowScrollHandler);
                        disposing && disposing.add(function() {
                            $(window).off('scroll', that._windowScrollHandler)
                        })
                    }
                }
            },
            _renderContent: function(contentElement, tableElement) {
                var that = this,
                    contentElement,
                    contentHeight,
                    rowHeight = that._rowHeight || 20,
                    virtualItemsCount = that._dataController.virtualItemsCount();
                that._tableElement = tableElement;
                contentElement.addClass(DATAGRID_CONTENT_CLASS);
                if (virtualItemsCount) {
                    tableElement.addClass(DATAGRID_TABLE_CONTENT_CLASS);
                    DX.translator.move(tableElement, {top: Math.floor(virtualItemsCount.begin * rowHeight)});
                    if (!contentElement.children().length)
                        contentElement.append(tableElement);
                    else
                        contentElement.children().first().replaceWith(tableElement);
                    if (contentElement.children().length === 1) {
                        contentElement.append(that._createTable());
                        that._contentHeight = 0
                    }
                    contentHeight = (virtualItemsCount.begin + virtualItemsCount.end + that._dataController.items().length) * rowHeight;
                    if (that._contentHeight !== contentHeight) {
                        that._contentHeight = contentHeight;
                        that._updateContainerHeight(contentElement.children().eq(1), contentHeight)
                    }
                }
                else
                    contentElement.replaceWith($('<div>').addClass(DATAGRID_CONTENT_CLASS).append(tableElement));
                return contentElement
            },
            setColumnWidths: function(widths) {
                this._setColumnWidthsCore(this._findContentElement().children(), widths)
            },
            _updateContent: function(tableElement, changeType) {
                var that = this,
                    contentElement = that._findContentElement(),
                    rowHeight = that._rowHeight || 20,
                    contentTable,
                    virtualItemsCount = that._dataController.virtualItemsCount();
                that.setColumnWidths();
                if (changeType === 'append' || changeType === 'prepend') {
                    contentTable = contentElement.children().first();
                    if (virtualItemsCount) {
                        tableElement.addClass(DATAGRID_TABLE_CONTENT_CLASS);
                        DX.translator.move(contentTable, {top: Math.floor(virtualItemsCount.begin * rowHeight)})
                    }
                    tableElement.find('tr')[changeType === 'append' ? 'appendTo' : 'prependTo'](contentTable)
                }
                else
                    that._renderContent(contentElement, tableElement);
                that._updateBorderLastRow()
            },
            _renderFreeSpaceRow: function(tableElement, columns) {
                var that = this,
                    i,
                    freeSpaceRowElement = that._createRow().hide(),
                    column;
                freeSpaceRowElement.addClass(DATAGRID_FREESPACE_CLASS).toggleClass(DATAGRID_COLUMN_LINES_CLASS, that.option('showColumnLines'));
                for (i = 0; i < columns.length; i++) {
                    column = {
                        command: utils.isDefined(columns[i].groupIndex) ? 'group' : '',
                        cssClass: utils.isDefined(columns[i].cssClass) ? columns[i].cssClass : ''
                    };
                    freeSpaceRowElement.append(that._createCell(null, null, null, column))
                }
                that._appendRow(tableElement, freeSpaceRowElement);
                that._freeSpaceRowElement = freeSpaceRowElement
            },
            _updateRowHeight: function() {
                var that = this,
                    tableHeight,
                    $element = that._element(),
                    itemsCount = that._dataController.items().length,
                    viewportHeight;
                if ($element && itemsCount > 0 && !that._rowHeight) {
                    tableHeight = that._tableElement.height();
                    if (that._freeSpaceRowElement && that._freeSpaceRowElement.is(':visible'))
                        tableHeight -= that._freeSpaceRowElement.height();
                    that._rowHeight = tableHeight / itemsCount;
                    if (that._rowHeight) {
                        that._updateContent(that._tableElement);
                        viewportHeight = that._hasHeight ? $element.height() : $(window).height();
                        that._dataController.setViewportSize(Math.round(viewportHeight / that._rowHeight))
                    }
                }
            },
            _updateContainerHeight: function(container, height) {
                var that = this,
                    columns = that._columnsController.getVisibleColumns(),
                    html = container.find('colgroup').prop('outerHTML') || dataGrid.createColGroup(columns).prop('outerHTML'),
                    freeSpaceCellsHtml = '',
                    i,
                    columnLinesClass = that.option('showColumnLines') ? DATAGRID_COLUMN_LINES_CLASS : '',
                    createFreeSpaceRowHtml = function(height) {
                        return '<tr style="height:' + height + 'px;" class="' + DATAGRID_FREESPACE_CLASS + ' ' + DATAGRID_ROW_CLASS + ' ' + columnLinesClass + '" >' + freeSpaceCellsHtml + '</tr>'
                    };
                for (i = 0; i < columns.length; i++)
                    freeSpaceCellsHtml += utils.isDefined(columns[i].groupIndex) ? '<td class="' + DATAGRID_GROUP_SPACE_CLASS + '"/>' : '<td />';
                while (height > PIXELS_LIMIT) {
                    html += createFreeSpaceRowHtml(PIXELS_LIMIT);
                    height -= PIXELS_LIMIT
                }
                html += createFreeSpaceRowHtml(height);
                container.addClass(DATAGRID_TABLE_CLASS);
                container.html(html)
            },
            _findContentElement: function() {
                var $element = this._element(),
                    $scrollableContent;
                if ($element) {
                    $scrollableContent = $element.find('.dx-scrollable-content');
                    if (!$scrollableContent)
                        $scrollableContent = $element;
                    return $scrollableContent.children().first()
                }
            },
            _findBottomLoadPanel: function() {
                var $bottomLoadPanel = this._element().find('.' + DATAGRID_BOTTOM_LOAD_PANEL_CLASS);
                if ($bottomLoadPanel.length)
                    return $bottomLoadPanel
            },
            _getRowElements: function() {
                return this._element().find('.dx-row:not(.' + DATAGRID_FREESPACE_CLASS + ')')
            },
            _updateBottomLoading: function() {
                var that = this,
                    scrollingOptions = that.option("scrolling"),
                    virtualMode = scrollingOptions && scrollingOptions.mode === 'virtual',
                    appendMode = scrollingOptions && scrollingOptions.mode === 'infinite',
                    showBottomLoading = !that._dataController.hasKnownLastPage() && that._dataController.isLoaded() && (virtualMode || appendMode),
                    bottomLoadPanelElement = that._findBottomLoadPanel();
                if (showBottomLoading) {
                    bottomLoadPanelElement = bottomLoadPanelElement || $('<div />').addClass(DATAGRID_BOTTOM_LOAD_PANEL_CLASS).append($('<div />').dxLoadIndicator());
                    bottomLoadPanelElement.appendTo(that._findContentElement());
                    bottomLoadPanelElement.show()
                }
                else if (bottomLoadPanelElement)
                    bottomLoadPanelElement.hide()
            },
            _updateBorderLastRow: function() {
                var that = this,
                    rowItems = that._getRowElements(),
                    isPagerVisible = that.getView('pagerView') && that.getView('pagerView').isVisible(),
                    tableElement = that._tableElement;
                that._element().find('.' + DATAGRID_LAST_ROW).removeClass(DATAGRID_LAST_ROW);
                var $lastFreespaceRow = tableElement.find('.' + DATAGRID_FREESPACE_CLASS).last();
                if (isPagerVisible && rowItems.length && $lastFreespaceRow.height() === 0)
                    $lastFreespaceRow.prev().addClass(DATAGRID_LAST_ROW)
            },
            _appendRow: function(tableElement, rowElement) {
                var that = this;
                if (that.option("rowTemplate") && that._delayedTemplates.length)
                    that._delayedTemplates.push({
                        container: tableElement,
                        template: appendElementTemplate,
                        options: rowElement
                    });
                else
                    tableElement.append(rowElement)
            },
            _updateNoDataText: function() {
                var noDataElement = this._element().find('.' + DATAGRID_NODATA_TEXT_CLASS),
                    isVisible = !this._dataController.items().length,
                    isLoading = this._dataController.isLoading(),
                    rtlEnabled = this.option("rtlEnabled"),
                    noDataElementCSSConfig = {};
                if (!noDataElement.length)
                    noDataElement = $('<span>').addClass(DATAGRID_NODATA_TEXT_CLASS).hide().appendTo(this._element());
                noDataElement.text(this.option("noDataText"));
                noDataElementCSSConfig = {
                    marginTop: -Math.floor(noDataElement.height() / 2),
                    marginRight: rtlEnabled ? -Math.floor(noDataElement.width() / 2) : 0,
                    marginLeft: rtlEnabled ? 0 : -Math.floor(noDataElement.width() / 2)
                };
                noDataElement.css(noDataElementCSSConfig);
                if (isVisible && !isLoading)
                    noDataElement.show();
                else
                    noDataElement.hide()
            },
            _createTable: function() {
                var that = this;
                return that.callBase().on("dxclick", '.dx-row', that.createAction(function(args) {
                        var e = args.jQueryEvent;
                        if (!$(e.target).closest('.' + DATAGRID_EDITOR_CELL_CLASS).length && !$(e.target).closest('a').length) {
                            that._rowClick(that.getRowIndex(e.currentTarget), e);
                            e.preventDefault()
                        }
                    }))
            },
            _rowClick: function(rowIndex, event) {
                var item = this._dataController.items()[rowIndex] || {};
                this.executeAction("rowClick", $.extend({
                    rowIndex: rowIndex,
                    columns: this._columnsController.getVisibleColumns(),
                    jQueryEvent: event,
                    rowElement: $(event.target).closest(".dx-row"),
                    evaluate: function(expr) {
                        var getter = DX.data.utils.compileGetter(expr);
                        return getter(item.data)
                    }
                }, item))
            },
            _renderTable: function(items) {
                var that = this,
                    itemsLength = items.length,
                    item,
                    $row,
                    $groupCell,
                    values,
                    columnsLength,
                    i,
                    j,
                    groupEmptyCellsCount,
                    $cells = [],
                    columnsCountBeforeGroups = 0,
                    columns = that._columnsController.getVisibleColumns(),
                    rowTemplate = that.option("rowTemplate"),
                    $table = that._createTable();
                $table.append(dataGrid.createColGroup(columns));
                for (i = 0; i < columns.length; i++)
                    if (columns[i].groupIndex !== undefined) {
                        columnsCountBeforeGroups = i;
                        break
                    }
                for (i = 0; i < itemsLength; i++) {
                    item = items[i];
                    item.rowIndex = i;
                    $cells = [];
                    if (item.groupIndex !== undefined) {
                        $row = that._createRow(item);
                        groupEmptyCellsCount = item.groupIndex + columnsCountBeforeGroups;
                        for (j = 0; j < groupEmptyCellsCount; j++)
                            $cells.push(that._createCell(null, item, i, {command: 'group'}));
                        if (columns[groupEmptyCellsCount].allowCollapsing)
                            $cells.push(that._createCell(!!item.isExpanded, item, i, {command: 'group'}));
                        else
                            $cells.push(that._createCell(null, item, i, {command: 'group'}));
                        $groupCell = that._createCell(item.values[item.groupIndex], item, i, columns[groupEmptyCellsCount]);
                        $groupCell.attr('colspan', columns.length - groupEmptyCellsCount - 1);
                        $cells.push($groupCell)
                    }
                    else if (rowTemplate)
                        that._renderTemplate($table, rowTemplate, $.extend({columns: columns}, item));
                    else {
                        values = item.values;
                        columnsLength = columns.length;
                        $row = that._createRow(item);
                        for (j = 0; j < columnsLength; j++)
                            $cells.push(that._createCell(values[j], item, i, utils.isDefined(columns[j].groupIndex) ? {command: 'group'} : columns[j], j))
                    }
                    if ($cells.length)
                        $row.append($cells);
                    that._rowPrepared($row, $.extend({columns: columns}, item));
                    that._appendRow($table, $row)
                }
                if (rowTemplate)
                    that._highlightSearchText($table);
                that._renderFreeSpaceRow($table, columns);
                return $table
            },
            _renderCore: function(change) {
                var that = this,
                    items = change && change.items || that._dataController.items(),
                    changeType = change && change.changeType,
                    $element = that._element(),
                    $root = $element.parent();
                $element.addClass(DATAGRID_ROWS_VIEW_CLASS).toggleClass(DATAGRID_NOWRAP_CLASS, !that.option("wordWrapEnabled"));
                var $table = that._renderTable(items);
                that._renderScrollable($table);
                that._updateContent($table, changeType);
                that._updateBottomLoading();
                that._updateNoDataText();
                if (!$root || $root.parent().length)
                    that.renderDelayedTemplates();
                that._lastColumnWidths = null
            },
            getRowIndex: function($row) {
                return this._getRowElements().index($row)
            },
            getRow: function(index) {
                var rows = this._getRowElements();
                if (rows.length > index)
                    return $(rows[index])
            },
            getCell: function(columnIndex, rowIndex) {
                var rows = this._getRowElements(),
                    cells;
                if (rows.length > 0 && rowIndex >= 0) {
                    rowIndex = rowIndex < rows.length ? rowIndex : rows.length - 1;
                    cells = rows[rowIndex].cells;
                    if (cells && cells.length > 0)
                        return $(cells[cells.length > columnIndex ? columnIndex : cells.length - 1])
                }
            },
            getTableFromCell: function($cell) {
                return $cell.closest("." + DATAGRID_ROWS_VIEW_CLASS + " ." + DATAGRID_TABLE_CLASS)
            },
            updateFreeSpaceRowHeight: function() {
                var that = this,
                    elementHeight,
                    contentElement = that._findContentElement(),
                    contentHeight = 0,
                    resultHeight;
                if (that._freeSpaceRowElement && contentElement) {
                    that._freeSpaceRowElement.hide();
                    elementHeight = that._element().height();
                    $.each(contentElement.children(), function() {
                        contentHeight += $(this).outerHeight()
                    });
                    resultHeight = elementHeight - contentHeight - that.getScrollbarWidth(true);
                    if (that._dataController.items().length > 0)
                        if (resultHeight > 0) {
                            that._freeSpaceRowElement.height(resultHeight);
                            that._freeSpaceRowElement.show()
                        }
                        else if (!that._hasHeight) {
                            var freespaceRowCount = that._dataController.pageSize() - that._dataController.items().length;
                            if (freespaceRowCount > 0 && that._dataController.pageCount() > 1) {
                                that._freeSpaceRowElement.height(freespaceRowCount * that._rowHeight);
                                that._freeSpaceRowElement.show()
                            }
                        }
                }
            },
            ctor: function(component) {
                this.callBase(component);
                this.scrollOffsetChanged = $.Callbacks()
            },
            init: function() {
                var that = this,
                    visibleColumnIndex;
                that.callBase();
                that._dataController = that.getController('data');
                that._columnsController.columnsChanged.add(function(e) {
                    var editorFactory,
                        $tables;
                    if (e.optionName === 'width') {
                        visibleColumnIndex = that._columnsController.getVisibleIndex(e.columnIndex);
                        if (visibleColumnIndex !== -1) {
                            $tables = that._findContentElement().children();
                            $.each($tables, function(key, table) {
                                $(table).find('col').eq(visibleColumnIndex).css('width', e.column.width)
                            });
                            if (e.column.resizedCallbacks)
                                e.column.resizedCallbacks.fire(e.column.width);
                            editorFactory = that.getController('editorFactory');
                            editorFactory && editorFactory.focus(editorFactory.focus())
                        }
                    }
                });
                that._rowHeight = 0;
                that._scrollTop = 0;
                that._hasHeight = false;
                that._dataController.changed.add(function(change) {
                    switch (change.changeType) {
                        case'refresh':
                        case'prepend':
                        case'append':
                            that.render(null, change);
                            break;
                        default:
                            that._update(change);
                            break
                    }
                });
                that._dataController.loadingChanged.add(function(isLoading, messageText) {
                    that.setLoading(isLoading, messageText)
                });
                that._delayedTemplates = [];
                that._templatesCache = {};
                that.createAction("rowClick");
                that.createAction("cellClick");
                that.createAction("cellHoverChanged", {excludeValidators: ['gesture']})
            },
            publicMethods: function() {
                return ['isScrollbarVisible', 'getTopVisibleRowData']
            },
            renderDelayedTemplates: function() {
                var templateParameters,
                    delayedTemplates = this._delayedTemplates;
                while (delayedTemplates.length) {
                    templateParameters = delayedTemplates.shift();
                    templateParameters.template.render(templateParameters.container, templateParameters.options);
                    this._highlightSearchText(templateParameters.container)
                }
            },
            getScrollbarWidth: function(isHorizontal) {
                var scrollableContainer = this._scrollableContainer && this._scrollableContainer.get(0),
                    scrollbarWidth = 0;
                if (scrollableContainer)
                    if (!isHorizontal)
                        scrollbarWidth = scrollableContainer.offsetWidth - scrollableContainer.clientWidth;
                    else
                        scrollbarWidth = scrollableContainer.offsetHeight - scrollableContainer.clientHeight;
                return scrollbarWidth
            },
            resize: function() {
                var that = this,
                    lastColumnWidths = that._lastColumnWidths || [],
                    columnWidths = that.getColumnWidths(),
                    columns = that._columnsController.getVisibleColumns(),
                    dxScrollable,
                    i;
                for (i = 0; i < columns.length; i++)
                    if (columns[i].resizedCallbacks && !utils.isDefined(columns[i].groupIndex) && lastColumnWidths[i] !== columnWidths[i])
                        columns[i].resizedCallbacks.fire(columnWidths[i]);
                that._lastColumnWidths = columnWidths;
                that._updateRowHeight();
                that._updateNoDataText();
                that.updateFreeSpaceRowHeight();
                that._updateBorderLastRow();
                dxScrollable = that._element().data('dxScrollable');
                if (dxScrollable)
                    dxScrollable.update();
                that.callBase()
            },
            scrollToPage: function(pageIndex) {
                var that = this,
                    scrollingMode = that.option('scrolling.mode'),
                    dataController = that._dataController,
                    pageSize = dataController ? dataController.pageSize() : 0,
                    scrollPosition;
                if (scrollingMode === 'virtual' || scrollingMode === 'infinite')
                    scrollPosition = pageIndex * that._rowHeight * pageSize;
                else
                    scrollPosition = 0;
                that.scrollTo({
                    y: scrollPosition,
                    x: 0
                })
            },
            scrollTo: function(location) {
                var $element = this._element(),
                    dxScrollable = $element && $element.data('dxScrollable');
                if (dxScrollable)
                    dxScrollable.scrollTo(location)
            },
            height: function(height) {
                var that = this,
                    $element = this._element();
                if (utils.isDefined(height)) {
                    that._hasHeight = height !== 'auto';
                    if ($element)
                        $element.height(height);
                    that._freeSpaceRowElement && that._freeSpaceRowElement.hide()
                }
                else
                    return $element ? $element.height() : 0
            },
            setLoading: function(isLoading, messageText) {
                var that = this,
                    loadPanel = that._loadPanel,
                    hasBottomLoadPanel = !!that._findBottomLoadPanel() && that._dataController.isLoaded(),
                    loadPanelOptions = that.option("loadPanel");
                if (loadPanel) {
                    loadPanel.option('message', messageText || loadPanelOptions.text);
                    loadPanel.option('visible', hasBottomLoadPanel ? false : isLoading)
                }
            },
            isScrollbarVisible: function() {
                var $element = this._element();
                return $element ? this._findContentElement().outerHeight() - $element.height() > 0 : false
            },
            setRowsOpacity: function(columnIndex, value) {
                var that = this,
                    $rows = that._getRowElements().not('.' + DATAGRID_GROUP_ROW_CLASS) || [];
                $.each($rows, function(_, row) {
                    $(row).children().eq(columnIndex).css({opacity: value})
                })
            },
            getTopVisibleItemIndex: function() {
                var that = this,
                    itemIndex,
                    prevOffsetTop = 0,
                    offsetTop = 0,
                    rowElements = that._getRowElements(),
                    scrollPosition = that._scrollTop,
                    contentElementOffsetTop = that._findContentElement().offset().top,
                    items = that._dataController.items();
                for (itemIndex = 0; itemIndex < items.length; itemIndex++) {
                    prevOffsetTop = offsetTop;
                    offsetTop = rowElements.eq(itemIndex).offset().top - contentElementOffsetTop;
                    if (offsetTop > scrollPosition) {
                        if (scrollPosition * 2 < offsetTop + prevOffsetTop && itemIndex)
                            itemIndex--;
                        break
                    }
                }
                if (itemIndex && itemIndex === items.length)
                    itemIndex--;
                return itemIndex
            },
            getTopVisibleRowData: function() {
                var itemIndex = this.getTopVisibleItemIndex(),
                    items = this._dataController.items();
                if (items[itemIndex])
                    return items[itemIndex].data
            },
            optionChanged: function(name, value, prevValue) {
                var that = this;
                switch (name) {
                    case'wordWrapEnabled':
                    case'hoverStateEnabled':
                    case'showColumnLines':
                    case'showRowLines':
                    case'rowAlternationEnabled':
                    case'rowTemplate':
                    case'cellPrepared':
                    case'rowPrepared':
                        that.render();
                        that.component.resize();
                        break;
                    case'scrolling':
                    case'rtlEnabled':
                        that._rowHeight = null;
                        that._tableElement = null;
                        break;
                    case"disabled":
                    case'loadPanel':
                        that._tableElement = null;
                        that.render();
                        that.component.resize();
                        break;
                    case'noDataText':
                        that._updateNoDataText();
                        break;
                    case'cellHoverChanged':
                        that.createAction("cellHoverChanged", {excludeValidators: ['gesture']});
                        that.render();
                        that.component.resize();
                        break;
                    case"rowClick":
                        that.createAction("rowClick");
                        break;
                    case"cellClick":
                        that.createAction("cellClick");
                        break
                }
            }
        });
        dataGrid.formatValue = formatValue;
        $.extend(dataGrid.__internals, {
            DATAGRID_CELL_CONTENT_CLASS: DATAGRID_CELL_CONTENT_CLASS,
            DATAGRID_GROUP_ROW_CLASS: DATAGRID_GROUP_ROW_CLASS,
            DATAGRID_SEARCH_TEXT_CLASS: DATAGRID_SEARCH_TEXT_CLASS,
            DATAGRID_ROWS_VIEW_CLASS: DATAGRID_ROWS_VIEW_CLASS,
            DATAGRID_TABLE_CLASS: DATAGRID_TABLE_CLASS,
            DATAGRID_FREESPACE_CLASS: DATAGRID_FREESPACE_CLASS,
            DATAGRID_BOTTOM_LOAD_PANEL_CLASS: DATAGRID_BOTTOM_LOAD_PANEL_CLASS,
            DATAGRID_NODATA_TEXT_CLASS: DATAGRID_NODATA_TEXT_CLASS,
            DATAGRID_ROW_HOVERED: DATAGRID_ROW_HOVERED,
            DATAGRID_GROUP_SPACE_CLASS: DATAGRID_GROUP_SPACE_CLASS,
            DATAGRID_GROUP_OPENED_CLASS: DATAGRID_GROUP_OPENED_CLASS,
            DATAGRID_GROUP_CLOSED_CLASS: DATAGRID_GROUP_CLOSED_CLASS,
            DATAGRID_NOWRAP_CLASS: DATAGRID_NOWRAP_CLASS,
            DATAGRID_ROW_LINES_CLASS: DATAGRID_ROW_LINES_CLASS,
            DATAGRID_COLUMN_LINES_CLASS: DATAGRID_COLUMN_LINES_CLASS,
            DATAGRID_ROW_ALTERNATION_CLASS: DATAGRID_ROW_ALTERNATION_CLASS
        });
        dataGrid.registerModule('rows', {
            defaultOptions: function() {
                return {
                        hoverStateEnabled: false,
                        cellHoverChanged: null,
                        scrolling: {
                            mode: 'standard',
                            preloadEnabled: false,
                            useNativeScrolling: 'auto'
                        },
                        loadPanel: {
                            enabled: true,
                            text: Globalize.localize("Loading"),
                            width: 200,
                            height: 70
                        },
                        rowClick: null,
                        cellClick: null,
                        rowTemplate: null,
                        columnAutoWidth: false,
                        noDataText: Globalize.localize("dxDataGrid-noDataText"),
                        wordWrapEnabled: false,
                        showColumnLines: true,
                        showRowLines: false,
                        rowAlternationEnabled: false,
                        cellPrepared: null,
                        rowPrepared: null,
                        activeStateEnabled: false
                    }
            },
            views: {rowsView: dataGrid.RowsView},
            extenders: {controllers: {data: {
                        _applyFilter: function() {
                            var that = this,
                                result = that.callBase();
                            if (result && result.done)
                                result.done(function() {
                                    that.getView('rowsView').scrollToPage(0)
                                });
                            return result
                        },
                        pageIndex: function(value) {
                            var that = this,
                                result = that.callBase(value);
                            if (result && result.done)
                                result.done(function() {
                                    that.getView('rowsView').scrollToPage(that.pageIndex())
                                });
                            return result
                        },
                        pageSize: function(value) {
                            var that = this,
                                result = that.callBase(value);
                            if (result && result.done)
                                result.done(function() {
                                    that.getView('rowsView').scrollToPage(that.pageIndex())
                                });
                            return result
                        },
                        _refreshDataSource: function() {
                            var that = this;
                            var changedHandler = function() {
                                    that.changed.remove(changedHandler);
                                    that.getView('rowsView').scrollToPage(0)
                                };
                            that.changed.add(changedHandler);
                            that.callBase()
                        }
                    }}}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.pager.js */
    (function($, DX) {
        var ui = DX.ui,
            events = ui.events,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var DATAGRID_PAGER_CLASS = "dx-datagrid-pager";
        var MAX_PAGES_COUNT = 10;
        dataGrid.PagerView = dataGrid.View.inherit({
            init: function() {
                var that = this,
                    dataController = that.getController('data');
                that._isVisible = false;
                dataController.changed.add(function() {
                    that.render()
                })
            },
            _getPager: function() {
                var $element = this._element();
                return $element && $element.data('dxPager')
            },
            _renderCore: function() {
                var that = this,
                    $element = that._element().addClass(DATAGRID_PAGER_CLASS),
                    pagerOptions = that.option('pager'),
                    dataController = that.getController('data'),
                    rtlEnabled = that.option('rtlEnabled');
                $element.dxPager({
                    maxPagesCount: MAX_PAGES_COUNT,
                    pageIndex: dataController.pageIndex() + 1,
                    pagesCount: dataController.pageCount(),
                    pageSize: dataController.pageSize(),
                    showPageSizes: pagerOptions && pagerOptions.showPageSizeSelector,
                    pageSizes: that.getPageSizes(),
                    rtlEnabled: rtlEnabled,
                    hasKnownLastPage: dataController.hasKnownLastPage(),
                    pageIndexChanged: function(pageIndex) {
                        window.setTimeout(function() {
                            dataController.pageIndex(pageIndex - 1)
                        })
                    },
                    pageSizeChanged: function(pageSize) {
                        window.setTimeout(function() {
                            dataController.pageSize(pageSize)
                        })
                    }
                })
            },
            getPageSizes: function() {
                var that = this,
                    dataController = that.getController('data'),
                    pagerOptions = that.option('pager'),
                    allowedPageSizes = pagerOptions && pagerOptions.allowedPageSizes,
                    pageSize = dataController.pageSize();
                if (!utils.isDefined(that._pageSizes) || $.inArray(pageSize, that._pageSizes) === -1) {
                    that._pageSizes = [];
                    if (pagerOptions)
                        if ($.isArray(allowedPageSizes))
                            that._pageSizes = allowedPageSizes;
                        else if (allowedPageSizes && pageSize > 1)
                            that._pageSizes = [Math.floor(pageSize / 2), pageSize, pageSize * 2]
                }
                return that._pageSizes
            },
            isVisible: function() {
                var that = this,
                    dataController = that.getController('data'),
                    pagerOptions = that.option('pager'),
                    pagerVisible = pagerOptions && pagerOptions.visible,
                    scrolling = that.option('scrolling');
                if (that._isVisible)
                    return true;
                if (pagerVisible === 'auto')
                    if (scrolling && (scrolling.mode === 'virtual' || scrolling.mode === 'infinite'))
                        pagerVisible = false;
                    else
                        pagerVisible = dataController.pageCount() > 1 || dataController.isLoaded() && !dataController.hasKnownLastPage();
                that._isVisible = pagerVisible;
                return pagerVisible
            },
            getHeight: function() {
                var pager = this._getPager();
                return pager && this.isVisible() ? pager.getHeight() : 0
            },
            optionChanged: function(name, value, prevValue) {
                var that = this;
                switch (name) {
                    case'paging':
                    case'pager':
                        that._pageSizes = null;
                    case'scrolling':
                        that._isVisible = false;
                        that.render();
                        if (name === 'pager')
                            that.component && that.component.resize();
                        break
                }
            }
        });
        dataGrid.registerModule('pager', {
            defaultOptions: function() {
                return {
                        paging: {
                            enabled: true,
                            pageSize: undefined,
                            pageIndex: undefined
                        },
                        pager: {
                            visible: 'auto',
                            showPageSizeSelector: false,
                            allowedPageSizes: 'auto'
                        }
                    }
            },
            views: {pagerView: dataGrid.PagerView}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.gridView.js */
    (function($, DX) {
        var dataGrid = DX.ui.dataGrid,
            utils = DX.utils;
        var DATAGRID_CLASS = "dx-datagrid",
            EMPTY_GRID_ROWS_HEIGHT = 100,
            LOADPANEL_MARGIN = 50,
            VIEW_NAMES = ['columnsSeparatorView', 'blockSeparatorView', 'trackerView', 'headerPanel', 'columnHeadersView', 'rowsView', 'columnChooserView', 'pagerView', 'draggingHeaderView', 'contextMenuView', 'errorView'];
        var mergeArraysByMaxValue = function(values1, values2) {
                var result = [],
                    i;
                if (values1 && values2 && values1.length && values1.length === values2.length)
                    for (i = 0; i < values1.length; i++)
                        result.push(values1[i] > values2[i] ? values1[i] : values2[i]);
                return result
            };
        dataGrid.createColGroup = function(columns) {
            var colgroupElement = $('<colgroup />'),
                columnsLength = columns.length,
                i;
            for (i = 0; i < columnsLength; i++)
                $('<col />').width(columns[i].width).appendTo(colgroupElement);
            return colgroupElement
        };
        dataGrid.GridView = dataGrid.View.inherit({
            _initResizeHandlers: function() {
                var that = this;
                if (!that._refreshSizesHandler) {
                    that._refreshSizesHandler = function(e) {
                        if (!e || e.changeType === 'refresh' || e.changeType === 'append')
                            that.resize()
                    };
                    that._dataController.changed.add(that._refreshSizesHandler);
                    that._columnHeadersView.sizeChanged.add(that._refreshSizesHandler)
                }
            },
            _synchronizeColumns: function() {
                var that = this,
                    rowsColumnWidths = that._rowsView.getColumnWidths(),
                    headerColumnWidths = that._columnHeadersView.getColumnWidths(),
                    unusedIndexes = {length: 0},
                    hasAutoWidth = false,
                    resultWidths = headerColumnWidths ? mergeArraysByMaxValue(rowsColumnWidths, headerColumnWidths) : rowsColumnWidths;
                $.each(that._columnsController.getVisibleColumns(), function(index) {
                    if (!this.width || this.width === 'auto')
                        hasAutoWidth = true;
                    if (this.width && this.width !== 'auto') {
                        resultWidths[index] = this.width;
                        unusedIndexes[index] = true;
                        unusedIndexes.length++
                    }
                });
                if (!hasAutoWidth && resultWidths.length) {
                    var totalWidth = that._getTotalWidth(resultWidths, that._groupElement.width() - that._rowsView.getScrollbarWidth());
                    if (totalWidth < that._groupElement.width() - that._rowsView.getScrollbarWidth())
                        resultWidths[resultWidths.length - 1] = 'auto'
                }
                if (that.option('columnAutoWidth') && resultWidths.length > 0)
                    that._processStretch(resultWidths, that._groupElement.width() - that._rowsView.getScrollbarWidth(), unusedIndexes);
                that._rowsView.setColumnWidths(resultWidths);
                that._columnHeadersView.setColumnWidths(resultWidths)
            },
            _processStretch: function(resultSizes, groupSize, unusedIndexes) {
                var tableSize = this._getTotalWidth(resultSizes, groupSize),
                    diff,
                    diffElement,
                    onePixelElementsCount,
                    i;
                diff = groupSize - tableSize;
                diffElement = Math.floor(diff / (resultSizes.length - unusedIndexes.length));
                onePixelElementsCount = diff - diffElement * (resultSizes.length - unusedIndexes.length);
                if (diff >= 0)
                    for (i = 0; i < resultSizes.length; i++) {
                        if (unusedIndexes[i])
                            continue;
                        resultSizes[i] += diffElement;
                        if (i < onePixelElementsCount)
                            resultSizes[i]++
                    }
            },
            _getTotalWidth: function(widths, groupWidth) {
                var result = 0,
                    width,
                    i;
                for (i = 0; i < widths.length; i++) {
                    width = widths[i];
                    if (width)
                        result += utils.isString(width) && width.slice(-1) === '%' ? Math.round(parseInt(width) * groupWidth / 100) : parseInt(width)
                }
                return result
            },
            getView: function(name) {
                return this.component._views[name]
            },
            getViews: function() {
                return this.component._views
            },
            resize: function() {
                var that = this,
                    dataController = that._dataController,
                    rootElementHeight = that._rootElement.height(),
                    loadPanelOptions = that.option('loadPanel');
                if (that._hasHeight && rootElementHeight > 0 && that.option('scrolling'))
                    that._rowsView.height(rootElementHeight - that._headerPanel.getHeight() - that._columnHeadersView.getHeight() - that._pagerView.getHeight());
                else if (!that._hasHeight && dataController.items().length === 0)
                    that._rowsView.height(loadPanelOptions && loadPanelOptions.visible ? loadPanelOptions.height + LOADPANEL_MARGIN : EMPTY_GRID_ROWS_HEIGHT);
                else
                    that._rowsView.height('auto');
                that._rowsView.resetColumnWidths();
                that._columnHeadersView.resetColumnWidths();
                that._columnHeadersView.setScrollerSpacing(that._rowsView.getScrollbarWidth());
                that._synchronizeColumns();
                $.each(VIEW_NAMES, function(index, viewName) {
                    var view = that.getView(viewName);
                    if (view)
                        view.resize()
                })
            },
            init: function() {
                var that = this;
                that._dataController = that.getController('data');
                that._columnsController = that.getController('columns');
                that._columnHeadersView = that.getView('columnHeadersView');
                that._headerPanel = that.getView('headerPanel');
                that._rowsView = that.getView('rowsView');
                that._pagerView = that.getView('pagerView');
                that._rowsView.scrollOffsetChanged.add(function(e) {
                    that._columnHeadersView.setScrollOffset(e.left)
                });
                that._dataController.changed.add(function() {
                    that.component._fireContentReadyAction()
                });
                that._options = {}
            },
            element: function() {
                return this._groupElement
            },
            render: function(rootElement) {
                var that = this,
                    isFirstRender,
                    isLoading,
                    groupElement = that._groupElement || $('<div />').addClass(DATAGRID_CLASS);
                that._rootElement = rootElement || that._rootElement;
                isFirstRender = !that._groupElement;
                that._groupElement = groupElement;
                $.each(VIEW_NAMES, function(index, viewName) {
                    var view = that.getView(viewName);
                    if (view)
                        view.render(groupElement)
                });
                if (isFirstRender) {
                    that._hasHeight = !!that._rootElement.height();
                    that._groupElement = groupElement;
                    groupElement.appendTo(that._rootElement);
                    that._rowsView.renderDelayedTemplates()
                }
                that._initResizeHandlers();
                that.resize();
                isLoading = that._dataController.isLoading();
                if (!isLoading)
                    that.component._fireContentReadyAction();
                that._rowsView.setLoading(isLoading)
            }
        });
        dataGrid.registerModule("gridView", {views: {gridView: dataGrid.GridView}});
        $.extend(dataGrid.__internals, {
            viewNames: VIEW_NAMES,
            DATAGRID_CLASS: DATAGRID_CLASS
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.columnsResizingReorderingModule.js */
    (function($, DX) {
        var ui = DX.ui,
            events = ui.events,
            addNamespace = events.addNamespace,
            utils = DX.utils,
            dataGrid = ui.dataGrid,
            fx = DX.fx;
        var DATAGRID_COLUMNS_SEPARATOR_CLASS = "dx-datagrid-columns-separator",
            DATAGRID_COLUMNS_SEPARATOR_TRANSPARENT = "dx-datagrid-columns-separator-transparent",
            DATAGRID_DRAGGING_HEADER_CLASS = "dx-datagrid-drag-header",
            DATAGRID_CELL_CONTENT_CLASS = "dx-datagrid-text-content",
            DATAGTID_HEADERS_ACTION_CLASS = "dx-datagrid-action-cursor",
            DATAGRID_TRACKER_CLASS = "dx-datagrid-tracker",
            DATAGRID_BLOCK_SEPARATOR_CLASS = "dx-block-separator",
            DATAGRID_HEADERS_DROP_HIGHLIGHT_CLASS = 'dx-datagrid-drop-highlight',
            DATAGRID_HEADER_ROW_CLASS = "dx-header-row",
            WIDGET_CLASS = "dx-widget",
            DATAGRID_MODULE_NAMESPACE = "dxDataGridResizingReordering",
            COLUMNS_SEPARATOR_TOUCH_TRACKER_WIDTH = 10,
            DRAGGING_DELTA = 5;
        var allowResizing = function(that) {
                return that.option("allowColumnResizing") || that.getController("columns").isColumnOptionUsed("allowResizing")
            };
        var allowReordering = function(that) {
                return that.option("allowColumnReordering") || that.getController("columns").isColumnOptionUsed("allowReordering")
            };
        dataGrid.getPointsByColumns = function(items, pointCreated, isVertical) {
            var cellsLength = items.length,
                cancel = false,
                i,
                point,
                item,
                offset,
                result = [],
                rtlEnabled,
                columnIndex = 0;
            for (i = 0; i <= cellsLength; i++) {
                if (i < cellsLength) {
                    item = items.eq(columnIndex);
                    offset = item.offset();
                    rtlEnabled = item.css('direction') === 'rtl'
                }
                point = {
                    index: i,
                    x: offset ? offset.left + (!isVertical && rtlEnabled ^ i === cellsLength ? item.outerWidth() : 0) : 0,
                    y: offset ? offset.top + (isVertical && i === cellsLength ? item.outerHeight() : 0) : 0,
                    columnIndex: columnIndex
                };
                if (pointCreated)
                    cancel = pointCreated(point);
                if (!cancel)
                    result.push(point);
                columnIndex++
            }
            return result
        };
        dataGrid.TrackerView = dataGrid.View.inherit({
            _renderCore: function(options) {
                this.callBase();
                this._element().addClass(DATAGRID_TRACKER_CLASS);
                this.hide()
            },
            init: function() {
                var that = this,
                    $element;
                that.callBase();
                that.getController("tablePosition").positionChanged.add(function(position) {
                    $element = that._element();
                    if ($element && $element.hasClass(DATAGRID_TRACKER_CLASS)) {
                        $element.css({top: position.top});
                        $element.height(position.height)
                    }
                })
            },
            isVisible: function() {
                return allowResizing(this)
            },
            show: function() {
                this._element().show()
            },
            hide: function() {
                this._element().hide()
            },
            setHeight: function(value) {
                this._element().height(value)
            }
        });
        dataGrid.ColumnsSeparatorView = dataGrid.View.inherit({
            _isShown: true,
            _renderCore: function(options) {
                this.callBase(options);
                this._element().addClass(DATAGRID_COLUMNS_SEPARATOR_CLASS);
                this._isShown = true;
                this.hide()
            },
            _subscribeToEvent: function() {
                var that = this,
                    $element;
                that.getController("tablePosition").positionChanged.add(function(position) {
                    $element = that._element();
                    if ($element) {
                        $element.css({top: position.top});
                        $element.height(position.height)
                    }
                })
            },
            isVisible: function() {
                return this.option('showColumnHeaders') && (allowReordering(this) || allowResizing(this))
            },
            init: function() {
                this.callBase();
                this._isTransparent = allowResizing(this);
                if (this.isVisible())
                    this._subscribeToEvent()
            },
            show: function(targetLocation) {
                var that = this,
                    $element = this._element(),
                    startAnimate = function(toOptions) {
                        fx.stop($element, true);
                        fx.animate($element, {
                            type: "slide",
                            from: {
                                width: 0,
                                display: toOptions.display
                            },
                            to: toOptions,
                            duration: 300,
                            easing: "swing"
                        })
                    };
                if ($element && !that._isShown)
                    if (targetLocation === "group")
                        startAnimate({
                            width: "50px",
                            display: "inline-block"
                        });
                    else if (targetLocation === "columnChooser")
                        startAnimate({
                            width: "100%",
                            display: "block"
                        });
                    else if (that._isTransparent)
                        $element.removeClass(DATAGRID_COLUMNS_SEPARATOR_TRANSPARENT);
                    else
                        $element.show();
                that._isShown = true
            },
            hide: function() {
                var $element = this._element();
                if ($element && this._isShown)
                    if (this._isTransparent)
                        $element.addClass(DATAGRID_COLUMNS_SEPARATOR_TRANSPARENT);
                    else
                        $element.hide();
                this._isShown = false
            },
            height: function(value) {
                var $element = this._element();
                if ($element)
                    if (utils.isDefined(value))
                        $element.height(value);
                    else
                        return $element.height()
            },
            width: function(value) {
                var $element = this._element();
                if ($element)
                    if (utils.isDefined(value))
                        $element.width(value);
                    else
                        return $element.width()
            },
            moveByX: function(outerX) {
                var $element = this._element();
                if ($element) {
                    $element.css("left", outerX - this._parentElement().offset().left);
                    this._testPosx = outerX
                }
            },
            changeCursor: function(cursorName) {
                cursorName = utils.isDefined(cursorName) ? cursorName : "";
                var $element = this._element();
                if ($element) {
                    $element.css('cursor', cursorName);
                    this._testCursorName = cursorName
                }
            }
        });
        dataGrid.BlockSeparatorView = dataGrid.ColumnsSeparatorView.inherit({
            _subscribeToEvent: function(){},
            _renderCore: function(options) {
                this._isTransparent = false;
                this.callBase(options);
                this._element().addClass(DATAGRID_BLOCK_SEPARATOR_CLASS).html('&nbsp;')
            },
            hide: function() {
                var that = this,
                    $parent = this._parentElement();
                that.callBase();
                if ($parent && !$parent.children('.' + DATAGRID_BLOCK_SEPARATOR_CLASS).length)
                    $parent.prepend(that._element())
            },
            isVisible: function() {
                var groupPanelOptions = this.option("groupPanel"),
                    columnChooserOptions = this.option('columnChooser');
                return groupPanelOptions && groupPanelOptions.visible || columnChooserOptions && columnChooserOptions.enabled
            }
        });
        dataGrid.DraggingHeaderView = dataGrid.View.inherit({
            _isDragging: false,
            _getDropOptions: function() {
                var that = this;
                if (that._dragOptions)
                    return {
                            sourceColumnIndex: that._dragOptions.columnIndex,
                            sourceColumnElement: that._dragOptions.columnElement,
                            sourceLocation: that._dragOptions.sourceLocation,
                            targetColumnIndex: that._dropColumnIndex,
                            targetLocation: that._dropLocation
                        }
            },
            _dropHeader: function(args) {
                var e = args.jQueryEvent,
                    that = e.data.that,
                    controller = that._controller;
                that._element().hide();
                if (controller && that._isDragging)
                    controller.drop(that._getDropOptions());
                that._element().appendTo(that._parentElement());
                that._dragOptions = null;
                that._isDragging = false;
                document.onselectstart = that._onSelectStart || null
            },
            _getDraggingPanelByPos: function(pos) {
                var that = this,
                    result;
                $.each(that._dragOptions.draggingPanels, function(index, draggingPanel) {
                    if (draggingPanel) {
                        var boundingRect = draggingPanel.getBoundingRect();
                        if (boundingRect && (boundingRect.bottom === undefined || pos.y < boundingRect.bottom) && (boundingRect.top === undefined || pos.y > boundingRect.top) && (boundingRect.left === undefined || pos.x > boundingRect.left) && (boundingRect.right === undefined || pos.x < boundingRect.right)) {
                            result = draggingPanel;
                            return false
                        }
                    }
                });
                return result
            },
            _pointCreated: function(point, columns, location, sourceColumn) {
                var targetColumn = columns[point.columnIndex],
                    prevColumn = columns[point.columnIndex - 1];
                switch (location) {
                    case"columnChooser":
                        return true;
                    case"headers":
                        return sourceColumn && !sourceColumn.allowReordering || (!targetColumn || !targetColumn.allowReordering) && (!prevColumn || !prevColumn.allowReordering);
                    default:
                        return columns.length === 0
                }
            },
            _moveHeader: function(args) {
                var e = args.jQueryEvent,
                    that = e.data.that,
                    columnElements,
                    pointsByColumns,
                    newLeft,
                    newTop,
                    moveDeltaX,
                    moveDeltaY,
                    eventData = events.eventData(e),
                    targetDraggingPanel,
                    controller = that._controller,
                    i,
                    params,
                    dragOptions = that._dragOptions,
                    isVerticalOrientation,
                    centerPosition,
                    axisName,
                    rtlEnabled;
                if (that._isDragging) {
                    moveDeltaX = Math.abs(eventData.x - dragOptions.columnElement.offset().left - dragOptions.deltaX);
                    moveDeltaY = Math.abs(eventData.y - dragOptions.columnElement.offset().top - dragOptions.deltaY);
                    if (that._element().is(':visible') || moveDeltaX > DRAGGING_DELTA || moveDeltaY > DRAGGING_DELTA) {
                        that._element().show();
                        newLeft = eventData.x - dragOptions.deltaX;
                        newTop = eventData.y - dragOptions.deltaY;
                        that._element().offset({
                            left: newLeft,
                            top: newTop
                        });
                        targetDraggingPanel = that._getDraggingPanelByPos(eventData);
                        if (targetDraggingPanel) {
                            rtlEnabled = that.option('rtlEnabled');
                            isVerticalOrientation = targetDraggingPanel.getName() === 'columnChooser';
                            axisName = isVerticalOrientation ? 'y' : 'x';
                            columnElements = targetDraggingPanel.getColumnElements() || [];
                            pointsByColumns = dataGrid.getPointsByColumns(columnElements, function(point) {
                                return that._pointCreated(point, targetDraggingPanel.getColumns(), targetDraggingPanel.getName(), dragOptions.sourceColumn)
                            }, axisName === 'y');
                            that._dropLocation = targetDraggingPanel.getName();
                            if (pointsByColumns.length > 0)
                                for (i = 0; i < pointsByColumns.length; i++) {
                                    centerPosition = pointsByColumns[i + 1] && (pointsByColumns[i][axisName] + pointsByColumns[i + 1][axisName]) / 2;
                                    if (centerPosition === undefined || (rtlEnabled && axisName === 'x' ? eventData[axisName] > centerPosition : eventData[axisName] < centerPosition)) {
                                        that._dropColumnIndex = pointsByColumns[i].columnIndex;
                                        params = that._getDropOptions();
                                        if (columnElements[i])
                                            params.targetColumnElement = columnElements.eq(i);
                                        else {
                                            params.targetColumnElement = columnElements.last();
                                            params.isLast = true
                                        }
                                        params.posX = pointsByColumns[i].x;
                                        controller.dock(params);
                                        break
                                    }
                                }
                            else {
                                that._dropColumnIndex = -1;
                                params = that._getDropOptions();
                                controller.dock(params)
                            }
                        }
                    }
                    e.preventDefault()
                }
            },
            _subscribeToEvents: function(rootElement) {
                var that = this;
                that._moveHeaderAction = this.createAction(this._moveHeader, {excludeValidators: ['gesture']});
                that._dropHeaderAction = this.createAction(this._dropHeader, {excludeValidators: ['gesture']});
                $(document).on(addNamespace('dxpointermove', DATAGRID_MODULE_NAMESPACE), {
                    that: that,
                    rootElement: rootElement
                }, that._moveHeaderAction);
                that._element().on(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE), {that: that}, that._dropHeaderAction);
                $(document).on(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE), {that: that}, that._dropHeaderAction)
            },
            _renderCore: function() {
                this._element().addClass(DATAGRID_DRAGGING_HEADER_CLASS + ' ' + DATAGRID_CELL_CONTENT_CLASS + ' ' + WIDGET_CLASS).css('display', 'none')
            },
            _afterRender: function($parent) {
                this._unsubscribeFromEvents();
                this._subscribeToEvents($parent)
            },
            _unsubscribeFromEvents: function() {
                if (this._dropHeaderAction) {
                    this._element().off(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE), this._dropHeaderAction);
                    $(document).off(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE), this._dropHeaderAction)
                }
                if (this._moveHeaderAction)
                    $(document).off(addNamespace('dxpointermove', DATAGRID_MODULE_NAMESPACE), this._moveHeaderAction)
            },
            dispose: function() {
                this._dragOptions = null;
                this._unsubscribeFromEvents();
                this._element().parent().find('.' + DATAGRID_DRAGGING_HEADER_CLASS).remove()
            },
            isVisible: function() {
                var columnsController = this.getController("columns"),
                    commonColumnSettings = columnsController.getCommonSettings();
                return this.option('showColumnHeaders') && (allowReordering(this) || commonColumnSettings.allowGrouping || commonColumnSettings.allowHiding)
            },
            init: function() {
                this.callBase();
                this._controller = this.getController("draggingHeader")
            },
            drag: function(options) {
                var that = this,
                    columnElement = options.columnElement;
                that._dragOptions = options;
                that._isDragging = true;
                that._dropColumnIndex = options.columnIndex;
                that._dropLocation = options.sourceLocation;
                that._onSelectStart = document.onselectstart;
                document.onselectstart = function() {
                    return false
                };
                that._element().css({
                    textAlign: columnElement && columnElement.css('text-align'),
                    height: columnElement && columnElement.height(),
                    width: columnElement && columnElement.width(),
                    whiteSpace: columnElement && columnElement.css('white-space')
                }).addClass(DATAGTID_HEADERS_ACTION_CLASS).text(options.sourceColumn.caption);
                that._element().appendTo($(document.body))
            }
        });
        dataGrid.ColumnsResizerViewController = dataGrid.ViewController.inherit({
            _pointCreated: function(point, cellsLength, columns) {
                var currentColumn,
                    nextColumn;
                if (point.index > 0 && point.index < cellsLength) {
                    point.columnIndex -= 1;
                    currentColumn = columns[point.columnIndex] || {};
                    nextColumn = columns[point.columnIndex + 1] || {};
                    return !(currentColumn.allowResizing && nextColumn.allowResizing)
                }
                return true
            },
            _getTargetPoint: function(pointsByColumns, currentX, deltaX) {
                if (pointsByColumns)
                    for (var i = 0; i < pointsByColumns.length; i++)
                        if (pointsByColumns[i].x - deltaX <= currentX && currentX <= pointsByColumns[i].x + deltaX)
                            return pointsByColumns[i];
                return null
            },
            _moveSeparator: function(args) {
                var e = args.jQueryEvent,
                    that = e.data,
                    pointsByColumns = that._pointsByColumns,
                    columnsSeparatorWidth = that._columnsSeparatorView.width(),
                    columnsSeparatorOffset = that._columnsSeparatorView._element().offset(),
                    deltaX = columnsSeparatorWidth / 2,
                    parentOffsetLeft = that._$parentContainer.offset().left,
                    eventData = events.eventData(e);
                if (that._isResizing) {
                    if (parentOffsetLeft <= eventData.x && eventData.x <= parentOffsetLeft + that._$parentContainer.width())
                        if (that._updateColumnsWidthIfNeeded(that._targetPoint.columnIndex, eventData.x)) {
                            that._columnsSeparatorView.moveByX(that._targetPoint.x + (eventData.x - that._resizingInfo.startPosX));
                            that._tablePositionController.update();
                            e.preventDefault()
                        }
                }
                else {
                    that._targetPoint = that._getTargetPoint(pointsByColumns, eventData.x, columnsSeparatorWidth);
                    that._isReadyResizing = false;
                    that._columnsSeparatorView.changeCursor();
                    if (that._targetPoint && columnsSeparatorOffset.top <= eventData.y && columnsSeparatorOffset.top + that._columnsSeparatorView.height() >= eventData.y) {
                        that._columnsSeparatorView.changeCursor('col-resize');
                        that._columnsSeparatorView.moveByX(that._targetPoint.x - deltaX);
                        that._isReadyResizing = true;
                        e.preventDefault()
                    }
                }
            },
            _endResizing: function(args) {
                var e = args.jQueryEvent,
                    that = e.data;
                if (that._isResizing) {
                    that._updatePointsByColumns();
                    that._resizingInfo = null;
                    that._columnsSeparatorView.hide();
                    that._columnsSeparatorView.changeCursor();
                    that._trackerView.hide();
                    that._isReadyResizing = false;
                    that._isResizing = false
                }
            },
            _setupResizingInfo: function(posX) {
                var that = this,
                    currentHeader = that._columnHeadersView.getHeaderElement(that._targetPoint.columnIndex),
                    nextHeader = that._columnHeadersView.getHeaderElement(that._targetPoint.columnIndex + 1);
                that._resizingInfo = {
                    startPosX: posX,
                    currentColumnWidth: currentHeader && currentHeader.length > 0 ? currentHeader.outerWidth() : 0,
                    nextColumnWidth: nextHeader && nextHeader.length > 0 ? nextHeader.outerWidth() : 0
                }
            },
            _startResizing: function(args) {
                var e = args.jQueryEvent,
                    that = e.data,
                    eventData = events.eventData(e);
                if (events.isTouchEvent(e)) {
                    that._targetPoint = that._getTargetPoint(that._pointsByColumns, eventData.x, COLUMNS_SEPARATOR_TOUCH_TRACKER_WIDTH);
                    if (that._targetPoint) {
                        that._columnsSeparatorView.moveByX(that._targetPoint.x - that._columnsSeparatorView.width() / 2);
                        that._isReadyResizing = true
                    }
                }
                if (that._isReadyResizing) {
                    if (that._targetPoint)
                        that._testColumnIndex = that._targetPoint.columnIndex;
                    that._setupResizingInfo(eventData.x);
                    that._columnsSeparatorView.show();
                    that._trackerView.show();
                    that._isResizing = true;
                    e.preventDefault()
                }
            },
            _generatePointsByColumns: function() {
                var that = this,
                    columns = that._columnsController ? that._columnsController.getVisibleColumns() : [],
                    cells = that._columnHeadersView.getColumnElements(),
                    pointsByColumns = [];
                if (cells && cells.length > 0)
                    pointsByColumns = dataGrid.getPointsByColumns(cells, function(point) {
                        return that._pointCreated(point, cells.length, columns)
                    });
                that._pointsByColumns = pointsByColumns
            },
            _unsubscribeFromEvents: function() {
                this._$parentContainer.off(addNamespace('dxpointermove', DATAGRID_MODULE_NAMESPACE));
                this._columnsSeparatorView._element().off(addNamespace('dxpointerdown', DATAGRID_MODULE_NAMESPACE));
                this._columnsSeparatorView._element().off(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE));
                $(document).off(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE))
            },
            _subscribeToEvents: function() {
                this._$parentContainer.on(addNamespace('dxpointermove', DATAGRID_MODULE_NAMESPACE), this, this.createAction(this._moveSeparator, {excludeValidators: ['gesture']}));
                this._$parentContainer.on(addNamespace('dxpointerdown', DATAGRID_MODULE_NAMESPACE), this, this.createAction(this._startResizing));
                this._columnsSeparatorView._element().on(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE), this, this.createAction(this._endResizing, {excludeValidators: ['gesture']}));
                $(document).on(addNamespace('dxpointerup', DATAGRID_MODULE_NAMESPACE), this, this.createAction(this._endResizing, {excludeValidators: ['gesture']}))
            },
            _updateColumnsWidthIfNeeded: function(columnIndex, posX) {
                var deltaX,
                    isUpdated = false,
                    nextCellWidth,
                    visibleColumns = this._columnsController.getVisibleColumns(),
                    columnsSeparatorWidth = this._columnsSeparatorView.width(),
                    cellWidth;
                deltaX = posX - this._resizingInfo.startPosX;
                if (this.option("rtlEnabled"))
                    deltaX = -deltaX;
                cellWidth = this._resizingInfo.currentColumnWidth + deltaX;
                nextCellWidth = this._resizingInfo.nextColumnWidth - deltaX;
                isUpdated = !(cellWidth <= columnsSeparatorWidth || nextCellWidth <= columnsSeparatorWidth);
                if (isUpdated) {
                    visibleColumns[columnIndex] && this._columnsController.columnOption(visibleColumns[columnIndex].initialIndex, 'width', Math.floor(cellWidth));
                    visibleColumns[columnIndex + 1] && this._columnsController.columnOption(visibleColumns[columnIndex + 1].initialIndex, 'width', Math.floor(nextCellWidth))
                }
                return isUpdated
            },
            _updatePointsByColumns: function() {
                var i,
                    point,
                    rtlEnabled = this.option("rtlEnabled"),
                    headerElement;
                for (i = 0; i < this._pointsByColumns.length; i++) {
                    point = this._pointsByColumns[i];
                    headerElement = this._columnHeadersView.getHeaderElement(point.columnIndex + 1);
                    if (headerElement && headerElement.length > 0)
                        point.x = headerElement.offset().left + (rtlEnabled ? headerElement.outerWidth() : 0)
                }
            },
            init: function() {
                var that = this,
                    gridView,
                    previousScrollbarVisibility,
                    generatePointsByColumnsScrollHandler = function(offset) {
                        if (that._scrollLeft !== offset.left) {
                            that._scrollLeft = offset.left;
                            that._generatePointsByColumns()
                        }
                    },
                    generatePointsByColumnsHandler = function() {
                        that._generatePointsByColumns()
                    };
                that.callBase();
                if (allowResizing(that)) {
                    that._columnsSeparatorView = that.getView("columnsSeparatorView");
                    that._columnHeadersView = that.getView("columnHeadersView");
                    that._trackerView = that.getView("trackerView");
                    that._rowsView = that.getView("rowsView");
                    that._columnsController = that.getController("columns");
                    that._tablePositionController = that.getController("tablePosition");
                    that._$parentContainer = that._columnsSeparatorView.component._element();
                    that._columnHeadersView.renderCompleted.add(generatePointsByColumnsHandler);
                    that._columnHeadersView.resizeCompleted.add(generatePointsByColumnsHandler);
                    that._columnsSeparatorView.renderCompleted.add(function() {
                        that._unsubscribeFromEvents();
                        that._subscribeToEvents()
                    });
                    that._rowsView.renderCompleted.add(function() {
                        that._rowsView.scrollOffsetChanged.remove(generatePointsByColumnsScrollHandler);
                        that._rowsView.scrollOffsetChanged.add(generatePointsByColumnsScrollHandler)
                    });
                    gridView = that.getView("gridView");
                    previousScrollbarVisibility = that._rowsView.getScrollbarWidth() !== 0;
                    that.getController("tablePosition").positionChanged.add(function() {
                        if (that._isResizing && !that._rowsView.isResizing) {
                            var scrollbarVisibility = that._rowsView.getScrollbarWidth() !== 0;
                            if (previousScrollbarVisibility !== scrollbarVisibility) {
                                previousScrollbarVisibility = scrollbarVisibility;
                                gridView.resize()
                            }
                            else {
                                that._rowsView.updateFreeSpaceRowHeight();
                                that._columnHeadersView.processSizeChanged()
                            }
                        }
                    })
                }
            }
        });
        dataGrid.TablePositionViewController = dataGrid.ViewController.inherit({
            update: function() {
                var $element = this._columnHeadersView._element(),
                    columnsHeadersHeight = this._columnHeadersView ? this._columnHeadersView.getHeight() : 0,
                    rowsHeight = this._rowsView ? this._rowsView.height() - this._rowsView.getScrollbarWidth(true) : 0;
                this.positionChanged.fire({
                    height: columnsHeadersHeight + rowsHeight,
                    top: $element && $element.length > 0 ? Math.floor($element[0].offsetTop) : 0
                })
            },
            init: function() {
                var that = this;
                that.callBase();
                that._columnHeadersView = this.getView("columnHeadersView");
                that._rowsView = this.getView("rowsView");
                that._pagerView = this.getView("pagerView");
                that._rowsView.resizeCompleted.add(function() {
                    that.update()
                })
            },
            ctor: function(component) {
                this.callBase(component);
                this.positionChanged = $.Callbacks()
            }
        });
        dataGrid.DraggingHeaderViewController = dataGrid.ViewController.inherit({
            _subscribeToEvent: function(draggingHeader, draggingPanels) {
                var that = this;
                $.each(draggingPanels, function(_, draggingPanel) {
                    if (draggingPanel) {
                        var columnElements = draggingPanel.getColumnElements() || [],
                            nameDraggingPanel = draggingPanel.getName(),
                            columns = draggingPanel.getColumns() || [];
                        $.each(columnElements, function(index, columnElement) {
                            $(columnElement).off(addNamespace('dxpointerdown', DATAGRID_MODULE_NAMESPACE));
                            if (draggingPanel.allowDragging(columns[index], draggingPanels))
                                $(columnElement).on(addNamespace('dxpointerdown', DATAGRID_MODULE_NAMESPACE), that.createAction(function(args) {
                                    var e = args.jQueryEvent,
                                        eventData = events.eventData(e);
                                    e.preventDefault();
                                    draggingHeader.drag({
                                        deltaX: eventData.x - $(e.currentTarget).offset().left,
                                        deltaY: eventData.y - $(e.currentTarget).offset().top,
                                        sourceColumn: columns[index],
                                        columnIndex: index,
                                        columnElement: $(columnElement),
                                        sourceLocation: draggingPanel.getName(),
                                        draggingPanels: draggingPanels
                                    })
                                }))
                        })
                    }
                })
            },
            _getSeparator: function(targetLocation) {
                return targetLocation === "headers" ? this._columnsSeparatorView : this._blockSeparatorView
            },
            hideSeparators: function() {
                var blockSeparator = this._blockSeparatorView,
                    columnsSeparator = this._columnsSeparatorView;
                this._animationColumnIndex = null;
                blockSeparator && blockSeparator.hide();
                columnsSeparator && columnsSeparator.hide()
            },
            init: function() {
                var that = this,
                    subscribeToEvent;
                that.callBase();
                that._columnsController = that.getController("columns");
                that._columnHeadersView = that.getView("columnHeadersView");
                that._columnsSeparatorView = that.getView("columnsSeparatorView");
                that._draggingHeaderView = that.getView("draggingHeaderView");
                that._rowsView = that.getView('rowsView');
                that._blockSeparatorView = that.getView("blockSeparatorView");
                that._headerPanelView = that.getView("headerPanel");
                that._columnChooserView = that.getView("columnChooserView");
                subscribeToEvent = function() {
                    if (that._draggingHeaderView)
                        that._subscribeToEvent(that._draggingHeaderView, [that._columnChooserView, that._columnHeadersView, that._headerPanelView])
                };
                that._columnHeadersView.renderCompleted.add(subscribeToEvent);
                that._headerPanelView.renderCompleted.add(subscribeToEvent);
                that._columnChooserView.renderCompleted.add(subscribeToEvent)
            },
            allowDrop: function(parameters) {
                return this._columnsController.allowMoveColumn(parameters.sourceColumnIndex, parameters.targetColumnIndex, parameters.sourceLocation, parameters.targetLocation)
            },
            allowDragColumn: function(columns, index, namePanel) {
                var column = columns[index],
                    i,
                    draggableColumnCount = 0;
                var allowDragFromHeaders = function(column) {
                        return column.allowReordering || column.allowGrouping || column.allowHiding
                    };
                if (!column)
                    return false;
                switch (namePanel) {
                    case"headers":
                        for (i = 0; i < columns.length; i++)
                            if (allowDragFromHeaders(columns[i]))
                                draggableColumnCount++;
                        return draggableColumnCount > 1 && allowDragFromHeaders(column);
                    case"group":
                        return column.allowGrouping;
                    case"columnChooser":
                        return column.allowHiding
                }
            },
            dock: function(parameters) {
                var that = this,
                    targetColumnIndex = parameters.targetColumnIndex,
                    sourceLocation = parameters.sourceLocation,
                    sourceColumnIndex = parameters.sourceColumnIndex,
                    sourceColumnElement = parameters.sourceColumnElement,
                    targetLocation = parameters.targetLocation,
                    separator = that._getSeparator(targetLocation),
                    hasTargetColumnIndex = targetColumnIndex >= 0;
                var showSeparator = function() {
                        if (that._animationColumnIndex !== targetColumnIndex) {
                            that.hideSeparators();
                            separator._element()[parameters.isLast ? 'insertAfter' : 'insertBefore'](parameters.targetColumnElement);
                            that._animationColumnIndex = targetColumnIndex;
                            separator.show(targetLocation)
                        }
                    };
                that._columnHeadersView._element().find('.' + DATAGRID_HEADER_ROW_CLASS).first().toggleClass(DATAGRID_HEADERS_DROP_HIGHLIGHT_CLASS, sourceLocation !== 'headers' && targetLocation === 'headers' && !hasTargetColumnIndex);
                if (separator) {
                    if (sourceColumnElement) {
                        sourceColumnElement.css({opacity: 0.5});
                        if (sourceLocation === 'headers')
                            that._rowsView.setRowsOpacity(sourceColumnIndex, 0.5)
                    }
                    if (that.allowDrop(parameters) && hasTargetColumnIndex)
                        if (targetLocation === 'group' || targetLocation === 'columnChooser')
                            showSeparator();
                        else {
                            that.hideSeparators();
                            separator.moveByX(parameters.posX - separator.width());
                            separator.show()
                        }
                    else
                        that.hideSeparators()
                }
            },
            drop: function(parameters) {
                var sourceColumnElement = parameters.sourceColumnElement;
                if (sourceColumnElement) {
                    sourceColumnElement.css({opacity: ''});
                    this._rowsView.setRowsOpacity(parameters.sourceColumnIndex, '');
                    this._columnHeadersView._element().find('.' + DATAGRID_HEADER_ROW_CLASS).first().removeClass(DATAGRID_HEADERS_DROP_HIGHLIGHT_CLASS)
                }
                if (this.allowDrop(parameters)) {
                    var separator = this._getSeparator(parameters.targetLocation);
                    if (separator)
                        separator.hide();
                    this._columnsController.moveColumn(parameters.sourceColumnIndex, parameters.targetColumnIndex, parameters.sourceLocation, parameters.targetLocation)
                }
            }
        });
        dataGrid.__internals = $.extend({}, dataGrid.__internals, {
            DATAGRID_COLUMNS_SEPARATOR_CLASS: DATAGRID_COLUMNS_SEPARATOR_CLASS,
            DATAGRID_COLUMNS_SEPARATOR_TRANSPARENT: DATAGRID_COLUMNS_SEPARATOR_TRANSPARENT,
            DATAGRID_DRAGGING_HEADER_CLASS: DATAGRID_DRAGGING_HEADER_CLASS,
            DATAGRID_CELL_CONTENT_CLASS: DATAGRID_CELL_CONTENT_CLASS,
            DATAGTID_HEADERS_ACTION_CLASS: DATAGTID_HEADERS_ACTION_CLASS,
            DATAGRID_TRACKER_CLASS: DATAGRID_TRACKER_CLASS,
            DATAGRID_MODULE_NAMESPACE: DATAGRID_MODULE_NAMESPACE,
            DATAGRID_HEADERS_DROP_HIGHLIGHT_CLASS: DATAGRID_HEADERS_DROP_HIGHLIGHT_CLASS,
            WIDGET_CLASS: WIDGET_CLASS
        });
        dataGrid.registerModule("columnsResizingReordering", {
            views: {
                columnsSeparatorView: dataGrid.ColumnsSeparatorView,
                blockSeparatorView: dataGrid.BlockSeparatorView,
                draggingHeaderView: dataGrid.DraggingHeaderView,
                trackerView: dataGrid.TrackerView
            },
            controllers: {
                draggingHeader: dataGrid.DraggingHeaderViewController,
                tablePosition: dataGrid.TablePositionViewController,
                columnsResizer: dataGrid.ColumnsResizerViewController
            }
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.contextMenuView.js */
    (function($, DX) {
        var ui = DX.ui,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        var DATAGRID_CLASS = "dx-datagrid",
            DATAGRID_CONTEXT_MENU = "dx-context-menu";
        dataGrid.ContextMenuView = dataGrid.View.inherit({
            viewNames: function() {
                return ["columnHeadersView"]
            },
            _renderCore: function() {
                var that = this;
                that._element().addClass(DATAGRID_CONTEXT_MENU).dxContextMenu({
                    positioningAction: function(actionArgs) {
                        var event = actionArgs.jQueryEvent,
                            $targetElement = $(event.target),
                            contextMenuInstance = actionArgs.component,
                            items = [];
                        $.each(that.viewNames(), function(index, viewName) {
                            var view = that.getView(viewName),
                                menuItems = view.getContextMenuItems($targetElement);
                            if (menuItems.length) {
                                items = menuItems;
                                return false
                            }
                        });
                        if (items.length)
                            contextMenuInstance.option('items', items);
                        else
                            actionArgs.canceled = true
                    },
                    itemClickAction: function(params) {
                        params.itemData.itemClickAction && params.itemData.itemClickAction(params)
                    },
                    rtlEnabled: that.option('rtlEnabled'),
                    cssClass: DATAGRID_CLASS,
                    target: that.component._element()
                })
            }
        });
        dataGrid.registerModule("contextMenu", {views: {contextMenuView: dataGrid.ContextMenuView}})
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.keyboardNavigation.js */
    (function($, DX) {
        var ui = DX.ui,
            utils = DX.utils,
            events = ui.events,
            dataGrid = ui.dataGrid;
        var DATAGRID_ROW_CLASS = "dx-row",
            DATAGRID_GROUP_ROW_CLASS = "dx-group-row",
            DATAGRID_EDITING_MODE_BATCH = "batch",
            DATAGRID_ROWS_VIEW_CLASS = "dx-datagrid-rowsview",
            DATAGRID_VIEWS = ["rowsView"];
        dataGrid.KeyboardNavigationController = dataGrid.ViewController.inherit({
            _focusView: function(view, viewIndex) {
                view.focus();
                this._focusedViews.viewIndex = viewIndex;
                this._focusedView = view
            },
            _initFocusedViews: function() {
                var that = this,
                    $cell,
                    $input,
                    clickHandler = that.createAction(function(e) {
                        var event = e.jQueryEvent,
                            $cell = $(event.currentTarget);
                        if (!that._editingController.isEditing())
                            if (that._isCellValid($cell)) {
                                $cell.focus();
                                that._focusView(event.data.view, event.data.viewIndex);
                                that._updateFocusedCellPosition($cell)
                            }
                            else
                                that._resetFocusedCell(that)
                    });
                that._focusedViews = [];
                $.each(DATAGRID_VIEWS, function(key, viewName) {
                    var view = that.getView(viewName);
                    if (view.isVisible())
                        that._focusedViews.push(view)
                });
                $.each(that._focusedViews, function(index, view) {
                    if (view)
                        view.renderCompleted.add(function() {
                            var $element = view._element();
                            $element.off(events.addNamespace("dxpointerdown", "dxDataGridKeyboardNavigation"), clickHandler);
                            $element.on(events.addNamespace("dxpointerdown", "dxDataGridKeyboardNavigation"), "." + DATAGRID_ROW_CLASS + " td", {
                                viewIndex: index,
                                view: view
                            }, clickHandler);
                            that._initKeyDownProcessor(that, $element, that._keyDownHandler);
                            if (that._focusedView && that._focusedView.name === view.name && that._isKeyDown) {
                                $cell = that._getFocusedCell();
                                if ($cell && $cell.length > 0) {
                                    that._focusView(view, index);
                                    if (that.getController('editorFactory').focus())
                                        that._focus($cell);
                                    setTimeout(function() {
                                        if (that._editingController.isEditing()) {
                                            $input = $cell.find('input').first();
                                            that._testFocusedInput = $input;
                                            $input.focus()
                                        }
                                        else {
                                            $cell.attr("tabindex", 0);
                                            $cell.focus()
                                        }
                                    })
                                }
                            }
                        })
                })
            },
            _initKeyDownProcessor: function(context, element, handler) {
                if (this._keyDownProcessor) {
                    this._keyDownProcessor.dispose();
                    this._keyDownProcessor = null
                }
                this._keyDownProcessor = new ui.HierarchicalKeyDownProcessor({
                    element: element,
                    context: context,
                    handler: handler
                })
            },
            _focusCell: function($cell) {
                var that = this;
                if ($cell) {
                    that.getController('editorFactory').focus($cell);
                    that._updateFocusedCellPosition($cell)
                }
            },
            _focusGroupRow: function($row) {
                if ($row) {
                    this.getController('editorFactory').focus($row);
                    this._focusedCellPosition.rowIndex = this._focusedView.getRowIndex($row)
                }
            },
            _getFocusedCell: function() {
                if (this._focusedView && this._focusedCellPosition)
                    return this._focusedView.getCell(this._focusedCellPosition.columnIndex, this._focusedCellPosition.rowIndex)
            },
            _moveScrollbar: function(keyCode) {
                var scrollable = this._focusedView ? this._focusedView._scrollable : null,
                    scrollOffset,
                    $cell,
                    table,
                    offsetTop,
                    offsetLeft,
                    targetLocationObject;
                if (scrollable) {
                    $cell = this._getFocusedCell();
                    if ($cell) {
                        table = this._focusedView.getTableFromCell($cell)[0];
                        offsetTop = $cell[0].offsetTop + table.offsetTop;
                        offsetLeft = $cell[0].offsetLeft + table.offsetLeft;
                        scrollOffset = scrollable.scrollOffset();
                        targetLocationObject = {
                            x: scrollOffset.left,
                            y: scrollOffset.top
                        };
                        switch (keyCode) {
                            case"downArrow":
                                if (offsetTop + $cell.height() > scrollOffset.top + scrollable.clientHeight())
                                    targetLocationObject.y += scrollable.clientHeight();
                                break;
                            case"upArrow":
                                if (offsetTop < scrollOffset.top)
                                    targetLocationObject.y -= scrollable.clientHeight();
                                break;
                            case"leftArrow":
                                if (offsetLeft < scrollOffset.left)
                                    targetLocationObject.x -= scrollable.clientWidth();
                                break;
                            case"rightArrow":
                                if (offsetLeft + $cell.width() > scrollOffset.left + scrollable.clientWidth())
                                    targetLocationObject.x += scrollable.clientWidth();
                                break
                        }
                        scrollable.scrollTo(targetLocationObject)
                    }
                }
            },
            _updateFocusedCellPosition: function($cell) {
                var that = this;
                if ($cell.length > 0)
                    this._focusedCellPosition = {
                        columnIndex: $cell[0].cellIndex,
                        rowIndex: $cell.parent().length > 0 && that._focusedView ? that._focusedView.getRowIndex($cell.parent()) : null
                    }
            },
            _isCellValid: function($cell) {
                var visibleColumns = this._columnsController.getVisibleColumns(),
                    columnIndex = $cell[0].cellIndex;
                return visibleColumns.length > columnIndex && !(visibleColumns[columnIndex].command || utils.isDefined(visibleColumns[columnIndex].groupIndex))
            },
            _isGroupRow: function($row) {
                return $row && $row.hasClass(DATAGRID_GROUP_ROW_CLASS)
            },
            _focus: function($cell) {
                var $row = $cell && $cell.parent();
                if (this._isGroupRow($row))
                    this._focusGroupRow($row);
                else
                    this._focusCell($cell)
            },
            _keyDownHandler: function(e) {
                var editingOptions = this.option("editing"),
                    isEditing = this._editingController.isEditing(),
                    pageIndex = this._dataController.pageIndex(),
                    pagesCount = this._dataController.pageCount(),
                    rowIndex = this._focusedCellPosition ? this._focusedCellPosition.rowIndex : null,
                    $row = this._focusedView && this._focusedView.getRow(rowIndex),
                    $cell;
                this._isKeyDown = true;
                switch (e.key) {
                    case"leftArrow":
                    case"rightArrow":
                        if (!isEditing && !this._isGroupRow($row)) {
                            $cell = this._getNextCell(e.key);
                            if ($cell && this._isCellValid($cell)) {
                                this._focusCell($cell);
                                this._moveScrollbar(e.key)
                            }
                            e.originalEvent.preventDefault()
                        }
                        break;
                    case"upArrow":
                    case"downArrow":
                        if (!isEditing) {
                            if (rowIndex === 0 || rowIndex === this._focusedView.getRowsCount() - 1);
                            $cell = this._getNextCell(e.key);
                            if ($cell && this._isCellValid($cell)) {
                                this._focus($cell);
                                this._moveScrollbar(e.key)
                            }
                            e.originalEvent.preventDefault()
                        }
                        break;
                    case"pageUp":
                        if (pageIndex > 0) {
                            this._dataController.pageIndex(pageIndex - 1);
                            e.originalEvent.preventDefault()
                        }
                        break;
                    case"pageDown":
                        if (pageIndex < pagesCount - 1) {
                            this._dataController.pageIndex(pageIndex + 1);
                            e.originalEvent.preventDefault()
                        }
                        break;
                    case"space":
                        if (this.option("selection") && this.option("selection").mode !== "none" && !isEditing)
                            this._selectionController.changeItemSelection(rowIndex, {
                                shift: e.shift,
                                control: e.ctrl
                            });
                        break;
                    case"A":
                        if (e.ctrl && this.option("selection") && this.option("selection").mode === "multiple")
                            this._selectionController.selectAll();
                        break;
                    case"tab":
                        if (isEditing && this._editingController.getEditMode() === DATAGRID_EDITING_MODE_BATCH && e.originalEvent.target) {
                            this._updateFocusedCellPosition($(e.originalEvent.target).closest('td'));
                            $cell = this._getNextCell("rightArrow");
                            this._focusCell($cell);
                            this._editingController.editCell(this._focusedCellPosition.rowIndex, this._focusedCellPosition.columnIndex);
                            e.originalEvent.preventDefault()
                        }
                        break;
                    case"enter":
                        if (this._isGroupRow($row)) {
                            if (this.option("grouping") && this.option("grouping").allowCollapsing) {
                                var path = this._dataController.getGroupPathByRowIndex(rowIndex);
                                if (path)
                                    this._dataController.changeGroupExpand(path)
                            }
                        }
                        else if (editingOptions.editEnabled)
                            if (isEditing) {
                                this._updateFocusedCellPosition($(e.originalEvent.target).closest('td'));
                                if (this._editingController.getEditMode() === DATAGRID_EDITING_MODE_BATCH)
                                    this._editingController.closeEditCell();
                                else
                                    setTimeout($.proxy(this._editingController.saveEditData, this._editingController))
                            }
                            else if (this._editingController.getEditMode() === DATAGRID_EDITING_MODE_BATCH)
                                this._editingController.editCell(rowIndex, this._focusedCellPosition.columnIndex);
                            else
                                this._editingController.editRow(rowIndex);
                        break;
                    case"escape":
                        if (editingOptions.editEnabled)
                            if (isEditing) {
                                this._updateFocusedCellPosition($(e.originalEvent.target).closest('td'));
                                if (this._editingController.getEditMode() === DATAGRID_EDITING_MODE_BATCH)
                                    this._editingController.closeEditCell();
                                else
                                    this._editingController.cancelEditData();
                                e.originalEvent.preventDefault()
                            }
                        break;
                    case"F":
                        if (e.ctrl && this.option("searchPanel") && this.option("searchPanel").visible) {
                            this._testHeaderPanelFocused = true;
                            this._headerPanel.focus();
                            e.originalEvent.preventDefault()
                        }
                        break
                }
            },
            _getNextCell: function(keyCode) {
                if (this._focusedView && this._focusedCellPosition) {
                    var columnIndex = this._focusedCellPosition.columnIndex,
                        visibleColumnsCount = this.getController("columns").getVisibleColumns().length,
                        rowIndex = this._focusedCellPosition.rowIndex;
                    switch (keyCode) {
                        case"rightArrow":
                            columnIndex = columnIndex < visibleColumnsCount - 1 ? columnIndex + 1 : columnIndex;
                            break;
                        case"leftArrow":
                            columnIndex = columnIndex > 0 ? columnIndex - 1 : columnIndex;
                            break;
                        case"upArrow":
                            rowIndex = rowIndex > 0 ? rowIndex - 1 : rowIndex;
                            break;
                        case"downArrow":
                            rowIndex = rowIndex < this._dataController.items().length - 1 ? rowIndex + 1 : rowIndex;
                            break
                    }
                    return this._focusedView.getCell(columnIndex, rowIndex)
                }
                return null
            },
            _resetFocusedCell: function(that) {
                var $cell = that._getFocusedCell();
                $cell && $cell.attr("tabindex", null);
                that._focusedCellPosition = null;
                that._isKeyDown = false
            },
            init: function() {
                var that = this;
                if (that.option("useKeyboard")) {
                    that._dataController = that.getController("data");
                    that._selectionController = that.getController("selection");
                    that._editingController = that.getController("editing");
                    that._headerPanel = that.getView("headerPanel");
                    that._pagerView = that.getView("pagerView");
                    that._columnsController = that.getController("columns");
                    that._focusedCellPosition = {
                        columnIndex: 0,
                        rowIndex: 0
                    };
                    that._dataController.changed.add(function(change) {
                        if (that._focusedCellPosition && change && change.changeType === 'prepend')
                            that._focusedCellPosition.rowIndex += change.items.length
                    });
                    that._initFocusedViews();
                    that._documentClickHandler = that.createAction(function(e) {
                        if (!$(e.jQueryEvent.target).closest("." + DATAGRID_ROWS_VIEW_CLASS).length)
                            that._resetFocusedCell(that)
                    });
                    $(document).on(events.addNamespace("dxpointerdown", "dxDataGridKeyboardNavigation"), that._documentClickHandler)
                }
            },
            dispose: function() {
                this.callBase();
                this._focusedView = null;
                this._focusedViews = null;
                this._keyDownProcessor && this._keyDownProcessor.dispose();
                $(document).off(events.addNamespace("dxpointerdown", "dxDataGridKeyboardNavigation"), this._documentClickHandler)
            }
        });
        $.extend(dataGrid.__internals, {
            DATAGRID_GROUP_ROW_CLASS: DATAGRID_GROUP_ROW_CLASS,
            DATAGRID_ROW_CLASS: DATAGRID_ROW_CLASS
        });
        dataGrid.registerModule("keyboardNavigation", {
            defaultOptions: function() {
                return {useKeyboard: true}
            },
            controllers: {keyboardNavigation: dataGrid.KeyboardNavigationController}
        })
    })(jQuery, DevExpress);
    /*! Module widgets-web, file ui.dataGrid.errorHandling.js */
    (function($, DX) {
        var ui = DX.ui,
            utils = DX.utils,
            dataGrid = ui.dataGrid;
        dataGrid.ErrorView = dataGrid.View.inherit({
            _renderCore: function() {
                this.toast({
                    type: 'error',
                    displayTime: 1000000,
                    position: {
                        my: 'center',
                        at: 'center'
                    },
                    contentReadyAction: function(e) {
                        this.content().on('dxclick', function() {
                            e.component.hide()
                        })
                    }
                })
            },
            toast: function(options) {
                return this._element().dxToast(options || 'instance')
            },
            isVisible: function() {
                return this.option('dataErrorVisible')
            },
            init: function() {
                var that = this,
                    dataController = that.getController('data');
                dataController.dataErrorOccurred.add(function(error) {
                    var message = error && error.message || error;
                    if (that.isVisible()) {
                        that.toast({message: message});
                        that.toast().show()
                    }
                })
            }
        });
        dataGrid.registerModule('errorHandling', {views: {errorView: dataGrid.ErrorView}})
    })(jQuery, DevExpress);
    DevExpress.MOD_WIDGETS_WEB = true
}
if (!DevExpress.MOD_FRAMEWORK) {
    if (!window.DevExpress)
        throw Error('Required module is not referenced: core');
    /*! Module framework, file framework.js */
    (function($, DX, undefined) {
        var mergeWithReplace = function(destination, source, needReplaceFn) {
                var result = [];
                for (var i = 0, destinationLength = destination.length; i < destinationLength; i++)
                    if (!needReplaceFn(destination[i], source))
                        result.push(destination[i]);
                result.push.apply(result, source);
                return result
            };
        var getMergeCommands = function() {
                return function(destination, source) {
                        return mergeWithReplace(destination, source, function(destObject, source) {
                                return $.grep(source, function(srcObject) {
                                        var match = destObject.option("id") === srcObject.option("id") && srcObject.option("id") || destObject.option("behavior") === srcObject.option("behavior") && destObject.option("behavior");
                                        if (match)
                                            destObject._element().remove();
                                        return match
                                    }).length
                            })
                    }
            };
        var resolvePropertyValue = function(command, containerOptions, propertyName) {
                var defaultOption = containerOptions ? containerOptions[propertyName] : undefined;
                return command.option(propertyName) || defaultOption
            };
        var resolveTextValue = function(command, containerOptions) {
                var hasIcon = !!command.option("icon") || command.option("iconSrc"),
                    titleValue = resolvePropertyValue(command, containerOptions, "title");
                return containerOptions.showText || !hasIcon ? titleValue : ""
            };
        var resolveIconValue = function(command, containerOptions, propertyName) {
                var hasText = !!command.option("title"),
                    iconValue = resolvePropertyValue(command, containerOptions, propertyName);
                return containerOptions.showIcon || !hasText ? iconValue : undefined
            };
        var resolveTypeValue = function(command, containerOptions) {
                return resolvePropertyValue(command, containerOptions, "type")
            };
        DX.framework = {utils: {
                mergeCommands: getMergeCommands(),
                commandToContainer: {
                    resolveTypeValue: resolveTypeValue,
                    resolveIconValue: resolveIconValue,
                    resolveTextValue: resolveTextValue,
                    resolvePropertyValue: resolvePropertyValue
                }
            }}
    })(jQuery, DevExpress);
    /*! Module framework, file framework.routing.js */
    (function($, DX) {
        var Class = DX.Class;
        DX.framework.Route = Class.inherit({
            _trimSeparators: function(str) {
                return str.replace(/^[\/.]+|\/+$/g, "")
            },
            _escapeRe: function(str) {
                return str.replace(/\W/g, "\\$1")
            },
            _checkConstraint: function(param, constraint) {
                param = String(param);
                if (typeof constraint === "string")
                    constraint = new RegExp(constraint);
                var match = constraint.exec(param);
                if (!match || match[0] !== param)
                    return false;
                return true
            },
            _ensureReady: function() {
                var that = this;
                if (this._patternRe)
                    return false;
                this._pattern = this._trimSeparators(this._pattern);
                this._patternRe = "";
                this._params = [];
                this._segments = [];
                this._separators = [];
                this._pattern.replace(/[^\/]+/g, function(segment, index) {
                    that._segments.push(segment);
                    if (index)
                        that._separators.push(that._pattern.substr(index - 1, 1))
                });
                $.each(this._segments, function(index) {
                    var isStatic = true,
                        segment = this,
                        separator = index ? that._separators[index - 1] : "";
                    if (segment.charAt(0) === ":") {
                        isStatic = false;
                        segment = segment.substr(1);
                        that._params.push(segment);
                        that._patternRe += "(?:" + separator + "([^/]*))";
                        if (segment in that._defaults)
                            that._patternRe += "?"
                    }
                    else
                        that._patternRe += separator + that._escapeRe(segment)
                });
                this._patternRe = new RegExp("^" + this._patternRe + "$")
            },
            ctor: function(pattern, defaults, constraints) {
                this._pattern = pattern || "";
                this._defaults = defaults || {};
                this._constraints = constraints || {}
            },
            parse: function(uri) {
                var that = this;
                this._ensureReady();
                var matches = this._patternRe.exec(uri);
                if (!matches)
                    return false;
                var result = $.extend({}, this._defaults);
                $.each(this._params, function(i) {
                    var index = i + 1;
                    if (matches.length >= index && matches[index])
                        result[this] = that.parseSegment(matches[index])
                });
                $.each(this._constraints, function(key) {
                    if (!that._checkConstraint(result[key], that._constraints[key])) {
                        result = false;
                        return false
                    }
                });
                return result
            },
            format: function(routeValues) {
                var that = this,
                    query = "";
                this._ensureReady();
                var mergeValues = $.extend({}, this._defaults),
                    useStatic = 0,
                    ret = [],
                    dels = [],
                    unusedRouteValues = {};
                $.each(routeValues, function(paramName, paramValue) {
                    routeValues[paramName] = that.formatSegment(paramValue);
                    if (!(paramName in mergeValues))
                        unusedRouteValues[paramName] = true
                });
                $.each(this._segments, function(index, segment) {
                    ret[index] = index ? that._separators[index - 1] : '';
                    if (segment.charAt(0) === ':') {
                        var paramName = segment.substr(1);
                        if (!(paramName in routeValues) && !(paramName in that._defaults)) {
                            ret = null;
                            return false
                        }
                        if (paramName in that._constraints && !that._checkConstraint(routeValues[paramName], that._constraints[paramName])) {
                            ret = null;
                            return false
                        }
                        if (paramName in routeValues) {
                            if (routeValues[paramName] !== undefined) {
                                mergeValues[paramName] = routeValues[paramName];
                                ret[index] += routeValues[paramName];
                                useStatic = index
                            }
                            delete unusedRouteValues[paramName]
                        }
                        else if (paramName in mergeValues) {
                            ret[index] += mergeValues[paramName];
                            dels.push(index)
                        }
                    }
                    else {
                        ret[index] += segment;
                        useStatic = index
                    }
                });
                $.each(mergeValues, function(key, value) {
                    if (!!value && $.inArray(":" + key, that._segments) === -1 && routeValues[key] !== value) {
                        ret = null;
                        return false
                    }
                });
                var unusedCount = 0;
                if (!$.isEmptyObject(unusedRouteValues)) {
                    query = "?";
                    $.each(unusedRouteValues, function(key) {
                        query += key + "=" + routeValues[key] + "&";
                        unusedCount++
                    });
                    query = query.substr(0, query.length - 1)
                }
                if (ret === null)
                    return false;
                if (dels.length)
                    $.map(dels, function(i) {
                        if (i >= useStatic)
                            ret[i] = ''
                    });
                var path = ret.join('');
                path = path.replace(/\/+$/, "");
                return {
                        uri: path + query,
                        unusedCount: unusedCount
                    }
            },
            formatSegment: function(value) {
                if ($.isArray(value) || $.isPlainObject(value))
                    return "json:" + encodeURIComponent(JSON.stringify(value));
                return encodeURIComponent(value)
            },
            parseSegment: function(value) {
                if (value.substr(0, 5) === "json:")
                    try {
                        return $.parseJSON(decodeURIComponent(value.substr(5)))
                    }
                    catch(x) {}
                return decodeURIComponent(value)
            }
        });
        DX.framework.MvcRouter = DX.Class.inherit({
            ctor: function() {
                this._registry = []
            },
            _trimSeparators: function(str) {
                return str.replace(/^[\/.]+|\/+$/g, "")
            },
            _createRoute: function(pattern, defaults, constraints) {
                return new DX.framework.Route(pattern, defaults, constraints)
            },
            register: function(pattern, defaults, constraints) {
                this._registry.push(this._createRoute(pattern, defaults, constraints))
            },
            _parseQuery: function(query) {
                var result = {},
                    values = query.split("&");
                $.each(values, function(index, value) {
                    var keyValuePair = value.split("=");
                    result[keyValuePair[0]] = decodeURIComponent(keyValuePair[1])
                });
                return result
            },
            parse: function(uri) {
                var that = this,
                    ret;
                uri = this._trimSeparators(uri);
                var parts = uri.split("?", 2),
                    path = parts[0],
                    query = parts[1];
                $.each(this._registry, function() {
                    var result = this.parse(path);
                    if (result !== false) {
                        ret = result;
                        if (query)
                            ret = $.extend(ret, that._parseQuery(query));
                        return false
                    }
                });
                return ret ? ret : false
            },
            format: function(obj) {
                var ret = false,
                    minUnusedCount = 99999;
                obj = obj || {};
                $.each(this._registry, function() {
                    var toFormat = $.extend(true, {}, obj);
                    var result = this.format(toFormat);
                    if (result !== false)
                        if (minUnusedCount > result.unusedCount) {
                            minUnusedCount = result.unusedCount;
                            ret = result.uri
                        }
                });
                return ret
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.command.js */
    (function($, DX) {
        var ui = DX.ui;
        DX.framework.dxCommand = DX.DOMComponent.inherit({
            ctor: function(element, options) {
                if ($.isPlainObject(element)) {
                    options = element;
                    element = $("<div />")
                }
                this.beforeExecute = $.Callbacks();
                this.afterExecute = $.Callbacks();
                this.callBase(element, options)
            },
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    action: null,
                    id: null,
                    title: "",
                    icon: "",
                    iconSrc: "",
                    visible: true,
                    disabled: false
                })
            },
            execute: function() {
                var isDisabled = this._options.disabled;
                if ($.isFunction(isDisabled))
                    isDisabled = !!isDisabled.apply(this, arguments);
                if (isDisabled)
                    throw new Error(DX.utils.stringFormat("Cannot execute command: {0}", this._options.id));
                this.beforeExecute.fire(arguments);
                this._createActionByOption("action", {allowedForGesture: true}).apply(this, arguments);
                this.afterExecute.fire(arguments)
            },
            _render: function() {
                this.callBase();
                this._element().addClass("dx-command")
            },
            _renderDisabledState: $.noop,
            _dispose: function() {
                this.callBase();
                this._element().removeData(this.NAME);
                this.beforeExecute.empty();
                this.afterExecute.empty()
            }
        });
        DX.registerComponent("dxCommand", DX.framework.dxCommand)
    })(jQuery, DevExpress);
    /*! Module framework, file framework.commandMapping.js */
    (function($, DX) {
        DX.framework.CommandMapping = DX.Class.inherit({
            ctor: function() {
                this._commandMappings = {};
                this._containerDefaults = {}
            },
            setDefaults: function(containerId, defaults) {
                this._containerDefaults[containerId] = defaults;
                return this
            },
            mapCommands: function(containerId, commandMappings) {
                var that = this;
                $.each(commandMappings, function(index, commandMapping) {
                    if (typeof commandMapping === "string")
                        commandMapping = {id: commandMapping};
                    var commandId = commandMapping.id;
                    var mappings = that._commandMappings[containerId] || {};
                    mappings[commandId] = $.extend({
                        showIcon: true,
                        showText: true
                    }, that._containerDefaults[containerId] || {}, commandMapping);
                    that._commandMappings[containerId] = mappings
                });
                this._initExistingCommands();
                return this
            },
            unmapCommands: function(containerId, commandIds) {
                var that = this;
                $.each(commandIds, function(index, commandId) {
                    var mappings = that._commandMappings[containerId] || {};
                    if (mappings)
                        delete mappings[commandId]
                });
                this._initExistingCommands()
            },
            getCommandMappingForContainer: function(commandId, containerId) {
                return (this._commandMappings[containerId] || {})[commandId]
            },
            checkCommandsExist: function(commands) {
                var that = this,
                    result = $.grep(commands, function(commandName, index) {
                        return $.inArray(commandName, that._existingCommands) < 0 && $.inArray(commandName, commands) === index
                    });
                if (result.length !== 0)
                    throw new Error("The '" + result.join("', '") + "' command" + (result.length === 1 ? " is" : "s are") + " not registred in the application's command mapping. See http://dxpr.es/1bTjfj1 for more details.");
            },
            load: function(config) {
                if (!config)
                    return;
                var that = this;
                $.each(config, function(name, container) {
                    that.setDefaults(name, container.defaults);
                    that.mapCommands(name, container.commands)
                });
                return this
            },
            _initExistingCommands: function() {
                var that = this;
                this._existingCommands = [];
                $.each(that._commandMappings, function(name, _commands) {
                    $.each(_commands, function(index, command) {
                        if ($.inArray(command.id, that._existingCommands) < 0)
                            that._existingCommands.push(command.id)
                    })
                })
            }
        });
        DX.framework.CommandMapping.defaultMapping = {
            "global-navigation": {
                defaults: {
                    showIcon: true,
                    showText: true
                },
                commands: []
            },
            "ios-header-toolbar": {
                defaults: {
                    showIcon: false,
                    showText: true,
                    location: "after"
                },
                commands: ["edit", "save", {
                        id: "back",
                        location: "before"
                    }, {
                        id: "cancel",
                        location: "before"
                    }, {
                        id: "create",
                        showIcon: true,
                        showText: false
                    }]
            },
            "ios-action-sheet": {
                defaults: {
                    showIcon: false,
                    showText: true
                },
                commands: []
            },
            "ios-view-footer": {
                defaults: {
                    showIcon: false,
                    showText: true
                },
                commands: [{
                        id: "delete",
                        type: "danger"
                    }]
            },
            "android-header-toolbar": {
                defaults: {
                    showIcon: true,
                    showText: false,
                    location: "after"
                },
                commands: [{
                        id: "back",
                        showIcon: false,
                        location: "before"
                    }, "create", "edit", "save", {
                        id: "cancel",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "delete",
                        showText: true,
                        location: "menu"
                    }]
            },
            "android-simple-toolbar": {
                defaults: {
                    showIcon: true,
                    showText: false,
                    location: "after"
                },
                commands: [{
                        id: "back",
                        showIcon: false,
                        location: "before"
                    }, {id: "create"}, {
                        id: "save",
                        showText: true,
                        location: "before"
                    }, {
                        id: "edit",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "cancel",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "delete",
                        showText: true,
                        location: "menu"
                    }]
            },
            "android-footer-toolbar": {
                defaults: {location: "after"},
                commands: [{
                        id: "create",
                        showText: false,
                        location: "center"
                    }, {
                        id: "edit",
                        showText: false,
                        location: "before"
                    }, {
                        id: "delete",
                        location: "menu"
                    }, {
                        id: "save",
                        showIcon: false,
                        location: "before"
                    }]
            },
            "tizen-header-toolbar": {
                defaults: {
                    showIcon: true,
                    showText: false,
                    location: "after"
                },
                commands: [{
                        id: "back",
                        showIcon: false,
                        location: "left"
                    }, "create", "edit", "save", {
                        id: "cancel",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "delete",
                        showText: true,
                        location: "menu"
                    }]
            },
            "tizen-footer-toolbar": {
                defaults: {location: "after"},
                commands: [{
                        id: "create",
                        showText: false
                    }, {
                        id: "edit",
                        showText: false,
                        location: "before"
                    }, {
                        id: "delete",
                        location: "menu"
                    }, {
                        id: "save",
                        showIcon: false,
                        location: "before"
                    }]
            },
            "tizen-simple-toolbar": {
                defaults: {
                    showIcon: true,
                    showText: false,
                    location: "after"
                },
                commands: [{
                        id: "back",
                        showIcon: false,
                        location: "before"
                    }, {id: "create"}, {
                        id: "save",
                        showText: true,
                        location: "before"
                    }, {
                        id: "edit",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "cancel",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "delete",
                        showText: true,
                        location: "menu"
                    }]
            },
            "generic-header-toolbar": {
                defaults: {
                    showIcon: false,
                    showText: true,
                    location: "after"
                },
                commands: ["edit", "save", {
                        id: "back",
                        location: "before"
                    }, {
                        id: "cancel",
                        location: "before"
                    }, {
                        id: "create",
                        showIcon: true,
                        showText: false
                    }]
            },
            "generic-view-footer": {
                defaults: {
                    showIcon: false,
                    showText: true
                },
                commands: [{
                        id: "delete",
                        type: "danger"
                    }]
            },
            "win8-appbar": {
                defaults: {location: "after"},
                commands: ["edit", "cancel", "save", "delete", {
                        id: "create",
                        location: "before"
                    }, {
                        id: "refresh",
                        location: "before"
                    }]
            },
            "win8-toolbar": {
                defaults: {
                    showText: false,
                    location: "before"
                },
                commands: [{id: "previousPage"}]
            },
            "win8-phone-appbar": {
                defaults: {location: "center"},
                commands: ["create", "edit", "cancel", "save", "refresh", {
                        id: "delete",
                        location: "menu"
                    }]
            },
            "win8-split-toolbar": {
                defaults: {
                    showIcon: true,
                    showText: false,
                    location: "right"
                },
                commands: [{
                        id: "back",
                        showIcon: false,
                        location: "left"
                    }, {id: "create"}, {
                        id: "save",
                        showText: true,
                        location: "left"
                    }, {
                        id: "edit",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "cancel",
                        showText: true,
                        location: "menu"
                    }, {
                        id: "delete",
                        showText: true,
                        location: "menu"
                    }]
            },
            "win8-master-detail-toolbar": {
                defaults: {
                    showText: false,
                    location: "left"
                },
                commands: ["back"]
            },
            "desktop-toolbar": {
                defaults: {
                    showIcon: false,
                    showText: true,
                    location: "after"
                },
                commands: ["cancel", "create", "edit", "save", {
                        id: "delete",
                        type: "danger"
                    }]
            }
        }
    })(jQuery, DevExpress);
    /*! Module framework, file framework.viewCache.js */
    (function($, DX, undefined) {
        var Class = DX.Class;
        DX.framework.ViewCache = Class.inherit({
            ctor: function(options) {
                this._cache = {};
                this.viewRemoved = $.Callbacks()
            },
            setView: function(key, viewInfo) {
                this._cache[key] = viewInfo
            },
            getView: function(key) {
                return this._cache[key]
            },
            removeView: function(key) {
                var result = this._cache[key];
                delete this._cache[key];
                this.viewRemoved.fire({viewInfo: result});
                return result
            },
            clear: function() {
                var that = this;
                $.each(this._cache, function(key) {
                    that.removeView(key)
                })
            },
            hasView: function(key) {
                return key in this._cache
            }
        });
        DX.framework.NullViewCache = DX.framework.ViewCache.inherit({setView: function(key, viewInfo) {
                this.callBase(key, viewInfo);
                this.removeView(key)
            }});
        DX.framework.ConditionalViewCacheDecorator = Class.inherit({
            ctor: function(options) {
                this._filter = options.filter;
                this._viewCache = options.viewCache;
                this.viewRemoved = this._viewCache.viewRemoved
            },
            setView: function(key, viewInfo) {
                this._viewCache.setView(key, viewInfo);
                if (!this._filter(key, viewInfo))
                    this._viewCache.removeView(key)
            },
            getView: function(key) {
                return this._viewCache.getView(key)
            },
            removeView: function(key) {
                return this._viewCache.removeView(key)
            },
            clear: function() {
                return this._viewCache.clear()
            },
            hasView: function(key) {
                return this._viewCache.hasView(key)
            }
        });
        var DEFAULT_VIEW_CACHE_CAPACITY = 10;
        DX.framework.CapacityViewCacheDecorator = Class.inherit({
            ctor: function(options) {
                this._keys = [];
                this._size = options.size || DEFAULT_VIEW_CACHE_CAPACITY;
                this._viewCache = options.viewCache;
                this.viewRemoved = this._viewCache.viewRemoved
            },
            setView: function(key, viewInfo) {
                if (!this.hasView(key)) {
                    if (this._keys.length == this._size)
                        this.removeView(this._keys[0]);
                    this._keys.push(key)
                }
                this._viewCache.setView(key, viewInfo)
            },
            getView: function(key) {
                var index = $.inArray(key, this._keys);
                if (index < 0)
                    return null;
                this._keys.push(key);
                this._keys.splice(index, 1);
                return this._viewCache.getView(key)
            },
            removeView: function(key) {
                var index = $.inArray(key, this._keys);
                if (index > -1)
                    this._keys.splice(index, 1);
                return this._viewCache.removeView(key)
            },
            clear: function() {
                this._keys = [];
                return this._viewCache.clear()
            },
            hasView: function(key) {
                return this._viewCache.hasView(key)
            }
        });
        DX.framework.HistoryDependentViewCacheDecorator = Class.inherit({
            ctor: function(options) {
                this._viewCache = options.viewCache || new DX.framework.ViewCache;
                this._navigationManager = options.navigationManager;
                this._navigationManager.itemRemoved.add($.proxy(this._onNavigationItemRemoved, this));
                this.viewRemoved = this._viewCache.viewRemoved
            },
            _onNavigationItemRemoved: function(item) {
                this.removeView(item.key)
            },
            setView: function(key, viewInfo) {
                this._viewCache.setView(key, viewInfo)
            },
            getView: function(key) {
                return this._viewCache.getView(key)
            },
            removeView: function(key) {
                return this._viewCache.removeView(key)
            },
            clear: function() {
                return this._viewCache.clear()
            },
            hasView: function(key) {
                return this._viewCache.hasView(key)
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.stateManager.js */
    (function($, DX, undefined) {
        var Class = DX.Class;
        DX.framework.MemoryKeyValueStorage = Class.inherit({
            ctor: function() {
                this.storage = {}
            },
            getItem: function(key) {
                return this.storage[key]
            },
            setItem: function(key, value) {
                this.storage[key] = value
            },
            removeItem: function(key) {
                delete this.storage[key]
            }
        });
        DX.framework.StateManager = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this.storage = options.storage || new DX.framework.MemoryKeyValueStorage;
                this.stateSources = options.stateSources || []
            },
            addStateSource: function(stateSource) {
                this.stateSources.push(stateSource)
            },
            removeStateSource: function(stateSource) {
                var index = $.inArray(stateSource, this.stateSources);
                if (index > -1) {
                    this.stateSources.splice(index, 1);
                    stateSource.removeState(this.storage)
                }
            },
            saveState: function() {
                var that = this;
                $.each(this.stateSources, function(index, stateSource) {
                    stateSource.saveState(that.storage)
                })
            },
            restoreState: function() {
                var that = this;
                $.each(this.stateSources, function(index, stateSource) {
                    stateSource.restoreState(that.storage)
                })
            },
            clearState: function() {
                var that = this;
                $.each(this.stateSources, function(index, stateSource) {
                    stateSource.removeState(that.storage)
                })
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.browserAdapters.js */
    (function($, DX, undefined) {
        var Class = DX.Class;
        var ROOT_PAGE_URL = "__root__",
            BUGGY_ANDROID_BUFFER_PAGE_URL = "__buffer__";
        DX.framework.DefaultBrowserAdapter = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this._window = options.window || window;
                this.popState = $.Callbacks();
                $(this._window).on("hashchange", $.proxy(this._onHashChange, this));
                this._tasks = DX.createQueue()
            },
            replaceState: function(uri) {
                var that = this;
                return this._addTask(function() {
                        uri = that._normalizeUri(uri);
                        that._window.history.replaceState(null, null, "#" + uri);
                        that._currentTask.resolve()
                    })
            },
            pushState: function(uri) {
                var that = this;
                return this._addTask(function() {
                        uri = that._normalizeUri(uri);
                        that._window.history.pushState(null, null, "#" + uri);
                        that._currentTask.resolve()
                    })
            },
            createRootPage: function() {
                return this.replaceState(ROOT_PAGE_URL)
            },
            _onHashChange: function() {
                if (this._currentTask)
                    this._currentTask.resolve();
                this.popState.fire()
            },
            back: function() {
                var that = this;
                return this._addTask(function() {
                        that._window.history.back()
                    })
            },
            getHash: function() {
                return this._normalizeUri(this._window.location.hash)
            },
            isRootPage: function() {
                return this.getHash() === ROOT_PAGE_URL
            },
            _normalizeUri: function(uri) {
                return (uri || "").replace(/^#+/, "").replace(":", "_")
            },
            _addTask: function(task) {
                var that = this,
                    d = $.Deferred();
                this._tasks.add(function() {
                    that._currentTask = d;
                    task();
                    return d
                });
                return d.promise()
            }
        });
        DX.framework.OldBrowserAdapter = DX.framework.DefaultBrowserAdapter.inherit({
            ctor: function() {
                this._innerEventCount = 0;
                this.callBase.apply(this, arguments);
                this._skipNextEvent = false
            },
            replaceState: function(uri) {
                var that = this;
                uri = that._normalizeUri(uri);
                if (that.getHash() !== uri) {
                    that._addTask(function() {
                        that._skipNextEvent = true;
                        that._window.history.back()
                    });
                    return that._addTask(function() {
                            that._skipNextEvent = true;
                            that._window.location.hash = uri
                        })
                }
                return $.Deferred().resolve().promise()
            },
            pushState: function(uri) {
                var that = this;
                uri = this._normalizeUri(uri);
                if (this.getHash() !== uri)
                    return that._addTask(function() {
                            that._skipNextEvent = true;
                            that._window.location.hash = uri
                        });
                return $.Deferred().resolve().promise()
            },
            createRootPage: function() {
                return this.pushState(ROOT_PAGE_URL)
            },
            _onHashChange: function() {
                var currentTask = this._currentTask;
                this._currentTask = null;
                if (this._skipNextEvent)
                    this._skipNextEvent = false;
                else
                    this.popState.fire();
                if (currentTask)
                    currentTask.resolve()
            }
        });
        DX.framework.BuggyAndroidBrowserAdapter = DX.framework.OldBrowserAdapter.inherit({createRootPage: function() {
                this.pushState(BUGGY_ANDROID_BUFFER_PAGE_URL);
                return this.callBase()
            }});
        DX.framework.HistorylessBrowserAdapter = DX.framework.DefaultBrowserAdapter.inherit({
            ctor: function(options) {
                options = options || {};
                this._window = options.window || window;
                this.popState = $.Callbacks();
                $(this._window).on("dxback", $.proxy(this._onHashChange, this));
                this._currentHash = this._window.location.hash
            },
            replaceState: function(uri) {
                this._currentHash = this._normalizeUri(uri);
                return $.Deferred().resolve().promise()
            },
            pushState: function(uri) {
                return this.replaceState(uri)
            },
            createRootPage: function() {
                return this.replaceState(ROOT_PAGE_URL)
            },
            getHash: function() {
                return this._normalizeUri(this._currentHash)
            },
            back: function() {
                return this.replaceState(ROOT_PAGE_URL)
            },
            _onHashChange: function() {
                var promise = this.back();
                this.popState.fire();
                return promise
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.navigationDevices.js */
    (function($, DX, undefined) {
        var Class = DX.Class;
        var SESSION_KEY = "dxPhoneJSApplication";
        DX.framework.HistoryBasedNavigationDevice = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this._browserAdapter = options.browserAdapter || this._createBrowserAdapter(options);
                this.uriChanged = $.Callbacks();
                this._browserAdapter.popState.add($.proxy(this._onPopState, this))
            },
            init: $.noop,
            getUri: function() {
                return this._browserAdapter.getHash()
            },
            setUri: function(uri, replaceCurrent) {
                if (replaceCurrent)
                    return this._browserAdapter.replaceState(uri);
                return this._browserAdapter.pushState(uri)
            },
            back: function() {
                return this._browserAdapter.back()
            },
            _onPopState: function() {
                this.uriChanged.fire(this.getUri())
            },
            _isBuggyAndroid2: function() {
                var realDevice = DX.devices.real();
                var version = realDevice.version;
                return realDevice.platform === "android" && version.length > 1 && (version[0] === 2 && version[1] < 4 || version[0] < 2)
            },
            _isBuggyAndroid4: function() {
                var realDevice = DX.devices.real();
                var version = realDevice.version;
                return realDevice.platform === "android" && version.length > 1 && version[0] === 4 && version[1] === 0
            },
            _createBrowserAdapter: function(options) {
                var sourceWindow = options.window || window,
                    supportPushReplace = sourceWindow.history.replaceState && sourceWindow.history.pushState;
                if (sourceWindow !== sourceWindow.top)
                    return new DX.framework.HistorylessBrowserAdapter(options);
                if (this._isBuggyAndroid4())
                    return new DX.framework.BuggyAndroidBrowserAdapter(options);
                if (this._isBuggyAndroid2() || !supportPushReplace)
                    return new DX.framework.OldBrowserAdapter(options);
                return new DX.framework.DefaultBrowserAdapter(options)
            }
        });
        DX.framework.StackBasedNavigationDevice = DX.framework.HistoryBasedNavigationDevice.inherit({
            ctor: function(options) {
                this.callBase(options);
                this.backInitiated = $.Callbacks();
                this._deferredNavigate = null;
                $(window).on("unload", this._saveBrowserState)
            },
            init: function() {
                var that = this;
                return that._prepareBrowserHistory().done(function() {
                        if (that._browserAdapter.isRootPage())
                            that._browserAdapter.pushState("")
                    })
            },
            setUri: function(uri) {
                return this.callBase(uri, !this._browserAdapter.isRootPage())
            },
            _saveBrowserState: function() {
                if (window.sessionStorage)
                    sessionStorage.setItem(SESSION_KEY, true)
            },
            _prepareBrowserHistory: function() {
                var hash = this.getUri();
                if (!window.sessionStorage || sessionStorage.getItem(SESSION_KEY))
                    return $.Deferred().resolve().promise();
                sessionStorage.removeItem(SESSION_KEY);
                this._browserAdapter.createRootPage();
                return this._browserAdapter.pushState(hash)
            },
            _onPopState: function() {
                var navigationPending = this._deferredNavigate && this._deferredNavigate.state() === "pending";
                if (this._browserAdapter.isRootPage())
                    if (navigationPending)
                        this._deferredNavigate.resolve();
                    else
                        this.backInitiated.fire();
                else {
                    if (!navigationPending)
                        this._deferredNavigate = $.Deferred().done($.proxy(this.callBase, this));
                    this.back()
                }
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.navigationManager.js */
    (function($, DX, undefined) {
        var Class = DX.Class;
        var NAVIGATION_TARGETS = {
                current: "current",
                blank: "blank",
                back: "back"
            },
            STORAGE_HISTORY_KEY = "__history";
        DX.framework.HistoryBasedNavigationManager = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this._currentItem = undefined;
                this._previousItem = undefined;
                this.navigating = $.Callbacks();
                this.navigated = $.Callbacks();
                this.navigationCanceled = $.Callbacks();
                this.navigatingBack = $.Callbacks();
                this.itemRemoved = $.Callbacks();
                this._createNavigationDevice(options)
            },
            _createNavigationDevice: function(options) {
                this._navigationDevice = options.navigationDevice || new DX.framework.HistoryBasedNavigationDevice;
                this._navigationDevice.uriChanged.add($.proxy(this._uriChangedHandler, this))
            },
            _uriChangedHandler: function(uri) {
                while (DX.hideTopOverlayCallback.fire());
                this.navigate(uri, {target: "none"})
            },
            _cancelNavigation: function(args) {
                this.navigationCanceled.fire(args)
            },
            _getDefaultOptions: function() {
                return {
                        direction: "none",
                        target: NAVIGATION_TARGETS.blank
                    }
            },
            _updateHistory: function(uri, options) {
                this._previousItem = this._currentItem;
                this._currentItem = {
                    uri: uri,
                    key: uri
                };
                if (options.target !== "none")
                    this._navigationDevice.setUri(uri, options.target === "current")
            },
            navigate: function(uri, options) {
                var that = this,
                    currentUri = that._currentItem && that._currentItem.uri,
                    args;
                if (uri === undefined)
                    uri = that._navigationDevice.getUri();
                if (/^_back$/.test(uri)) {
                    that.back();
                    return
                }
                options = $.extend(that._getDefaultOptions(), options || {});
                args = {
                    currentUri: currentUri,
                    uri: uri,
                    cancel: false,
                    navigateWhen: [],
                    options: options
                };
                that.navigating.fire(args);
                uri = args.uri;
                if (args.cancel || currentUri === uri && !that._forceNavigate)
                    that._cancelNavigation(args);
                else {
                    that._forceNavigate = false;
                    $.when.apply($, args.navigateWhen).done(function() {
                        DX.utils.executeAsync(function() {
                            that._updateHistory(uri, options);
                            that.navigated.fire({
                                uri: uri,
                                previousUri: currentUri,
                                options: options,
                                item: that._currentItem
                            })
                        })
                    })
                }
            },
            back: function() {
                return this._navigationDevice.back()
            },
            previousItem: function() {
                return this._previousItem
            },
            currentItem: function() {
                return this._currentItem
            },
            rootUri: function() {
                return this._currentItem && this._currentItem.uri
            },
            canBack: function() {
                return true
            },
            saveState: $.noop,
            restoreState: $.noop,
            removeState: $.noop
        });
        DX.framework.StackBasedNavigationManager = DX.framework.HistoryBasedNavigationManager.inherit({
            ctor: function(options) {
                options = options || {};
                this.callBase(options);
                this._createNavigationStacks(options);
                DX.hardwareBackButton.add($.proxy(this._deviceBackInitiated, this));
                this._stateStorageKey = options.stateStorageKey || STORAGE_HISTORY_KEY
            },
            init: function() {
                return this._navigationDevice.init()
            },
            _createNavigationDevice: function(options) {
                if (!options.navigationDevice)
                    options.navigationDevice = new DX.framework.StackBasedNavigationDevice;
                this.callBase(options);
                this._navigationDevice.backInitiated.add($.proxy(this._deviceBackInitiated, this))
            },
            _uriChangedHandler: function(uri) {
                this.navigate(uri)
            },
            _createNavigationStacks: function(options) {
                this.navigationStacks = {};
                this._keepPositionInStack = options.keepPositionInStack;
                this.currentStack = new DX.framework.NavigationStack
            },
            _deviceBackInitiated: function() {
                if (!DX.hideTopOverlayCallback.fire())
                    this.back({isHardwareButton: true});
                else
                    this._restoreDevicePreviousUri()
            },
            _restoreDevicePreviousUri: function() {
                var currentUri = this._currentItem && this._currentItem.uri;
                this._navigationDevice.setUri(currentUri)
            },
            _cancelNavigation: function(args) {
                this._restoreDevicePreviousUri();
                this.callBase(args)
            },
            _getDefaultOptions: function() {
                return {target: NAVIGATION_TARGETS.blank}
            },
            _createNavigationStack: function() {
                var result = new DX.framework.NavigationStack;
                result.itemsRemoved.add($.proxy(this._removeItems, this));
                return result
            },
            _setCurrentStack: function(stackKey) {
                if (!(stackKey in this.navigationStacks))
                    this.navigationStacks[stackKey] = this._createNavigationStack();
                this.currentStack = this.navigationStacks[stackKey];
                this.currentStackKey = stackKey
            },
            _updateHistory: function(uri, options) {
                var isRoot = options.root,
                    forceIsRoot = isRoot,
                    forceToRoot = false,
                    stackKey = options.stack || (isRoot ? uri : this.currentStackKey || uri),
                    previousStack = this.currentStack,
                    keepPositionInStack = options.keepPositionInStack !== undefined ? options.keepPositionInStack : this._keepPositionInStack;
                this._setCurrentStack(stackKey);
                if (isRoot || !this.currentStack.items.length) {
                    forceToRoot = this.currentStack === previousStack;
                    forceIsRoot = true
                }
                if (isRoot && this.currentStack.items.length) {
                    if (!keepPositionInStack || forceToRoot) {
                        this.currentStack.currentIndex = 0;
                        if (this.currentItem().uri !== uri)
                            this.currentStack.navigate(uri, true)
                    }
                }
                else {
                    var prevIndex = this.currentStack.currentIndex,
                        prevItem = this.currentItem() || {};
                    switch (options.target) {
                        case NAVIGATION_TARGETS.blank:
                            this.currentStack.navigate(uri);
                            break;
                        case NAVIGATION_TARGETS.current:
                            this.currentStack.navigate(uri, true);
                            break;
                        case NAVIGATION_TARGETS.back:
                            if (this.currentStack.currentIndex > 0)
                                this.currentStack.back(uri);
                            else
                                this.currentStack.navigate(uri, true);
                            break;
                        default:
                            throw Error(DX.utils.stringFormat("Unknown navigation target: \"{0}\". Use the DevExpress.framework.StackBasedNavigationManager.NAVIGATION_TARGETS enumerable values", options.target));
                    }
                    if (options.direction === undefined) {
                        var indexDelta = this.currentStack.currentIndex - prevIndex;
                        if (indexDelta < 0)
                            options.direction = this.currentStack.currentItem().backDirection || "backward";
                        else if (indexDelta > 0 && this.currentStack.currentIndex > 0)
                            options.direction = "forward";
                        else
                            options.direction = "none"
                    }
                    prevItem.backDirection = options.direction === "forward" ? "backward" : "none"
                }
                options.root = forceIsRoot;
                this._currentItem = this.currentStack.currentItem();
                this._restoreDevicePreviousUri()
            },
            _removeItems: function(items) {
                var that = this;
                $.each(items, function(index, item) {
                    that.itemRemoved.fire(item)
                })
            },
            back: function(options) {
                options = options || {};
                var navigatingBackArgs = $.extend({cancel: false}, options);
                this.navigatingBack.fire(navigatingBackArgs);
                if (navigatingBackArgs.cancel) {
                    this._restoreDevicePreviousUri();
                    return
                }
                var item = this.previousItem(navigatingBackArgs.stack);
                if (item)
                    this.navigate(item.uri, {
                        stack: navigatingBackArgs.stack,
                        target: NAVIGATION_TARGETS.back,
                        item: item
                    });
                else
                    this.callBase()
            },
            rootUri: function() {
                return this.currentStack.items.length ? this.currentStack.items[0].uri : this.callBase()
            },
            canBack: function(stackKey) {
                var stack = stackKey ? this.navigationStacks[stackKey] : this.currentStack;
                return stack.canBack()
            },
            saveState: function(storage) {
                if (this.currentStack.items.length) {
                    var state = {
                            items: this.currentStack.items,
                            currentIndex: this.currentStack.currentIndex,
                            currentStackKey: this.currentStack.items[0].uri
                        };
                    var json = JSON.stringify(state);
                    storage.setItem(this._stateStorageKey, json)
                }
                else
                    this.removeState(storage)
            },
            restoreState: function(storage) {
                if (this.disableRestoreState)
                    return;
                var json = storage.getItem(this._stateStorageKey);
                if (json)
                    try {
                        var state = JSON.parse(json),
                            stack = this._createNavigationStack();
                        if (!state.items[0].uri)
                            throw Error("Error while application state restoring. State has been cleared. Refresh the page");
                        stack.items = state.items;
                        stack.currentIndex = state.currentIndex;
                        this.navigationStacks[stack.items[0].uri] = stack;
                        this.currentStackKey = state.currentStackKey;
                        this.currentStack = this.navigationStacks[this.currentStackKey];
                        this._currentItem = this.currentStack.currentItem();
                        this._navigationDevice.setUri(this.currentItem().uri);
                        this._forceNavigate = true
                    }
                    catch(e) {
                        this.removeState(storage);
                        throw e;
                    }
            },
            removeState: function(storage) {
                storage.removeItem(this._stateStorageKey)
            },
            currentIndex: function() {
                return this.currentStack.currentIndex
            },
            previousItem: function(stackKey) {
                var stack = stackKey ? this.navigationStacks[stackKey] : this.currentStack;
                return stack.previousItem()
            },
            getItemByIndex: function(index) {
                return this.currentStack.items[index]
            },
            clearHistory: function() {
                this.currentStack.clear()
            }
        });
        DX.framework.NavigationStack = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this.itemsRemoved = $.Callbacks();
                this.clear()
            },
            currentItem: function() {
                return this.items[this.currentIndex]
            },
            previousItem: function() {
                return this.items.length > 1 ? this.items[this.currentIndex - 1] : undefined
            },
            canBack: function() {
                return this.currentIndex > 0
            },
            clear: function() {
                this._deleteItems(this.items);
                this.items = [];
                this.currentIndex = -1
            },
            back: function(uri) {
                this.currentIndex--;
                if (this.currentIndex < 0)
                    throw Error("Unable to go back");
                var currentItem = this.currentItem();
                if (currentItem.uri !== uri)
                    this._updateItem(this.currentIndex, uri)
            },
            forward: function() {
                this.currentIndex++;
                if (this.currentIndex >= this.items.length)
                    throw Error("Unable to go forward");
            },
            navigate: function(uri, replaceCurrent) {
                if (this.currentIndex < this.items.length && this.currentIndex > -1 && this.items[this.currentIndex].uri === uri)
                    return;
                if (replaceCurrent && this.currentIndex > -1)
                    this.currentIndex--;
                if (this.currentIndex + 1 < this.items.length && this.items[this.currentIndex + 1].uri === uri)
                    this.currentIndex++;
                else {
                    var toDelete = this.items.splice(this.currentIndex + 1, this.items.length - this.currentIndex - 1);
                    this.items.push({});
                    this.currentIndex++;
                    this._updateItem(this.currentIndex, uri);
                    this._deleteItems(toDelete)
                }
                return this.currentItem()
            },
            _updateItem: function(index, uri) {
                var item = this.items[index];
                item.uri = uri;
                item.key = this.items[0].uri + "_" + index + "_" + uri
            },
            _deleteItems: function(items) {
                if (items)
                    this.itemsRemoved.fire(items)
            }
        });
        DX.framework.HistoryBasedNavigationManager.NAVIGATION_TARGETS = NAVIGATION_TARGETS
    })(jQuery, DevExpress);
    /*! Module framework, file framework.actionExecutors.js */
    (function($, DX, undefined) {
        DX.framework.createActionExecutors = function(app) {
            return {
                    routing: {execute: function(e) {
                            var action = e.action,
                                routeValues,
                                options,
                                uri;
                            if ($.isPlainObject(action)) {
                                routeValues = action.routeValues;
                                if (routeValues && $.isPlainObject(routeValues))
                                    options = action.options;
                                else
                                    routeValues = action;
                                uri = app.router.format(routeValues);
                                app.navigate(uri, options);
                                e.handled = true
                            }
                        }},
                    hash: {execute: function(e) {
                            if (typeof e.action !== "string" || e.action.charAt(0) !== "#")
                                return;
                            var uriTemplate = e.action.substr(1),
                                args = e.args[0],
                                uri = uriTemplate;
                            var defaultEvaluate = function(expr) {
                                    var getter = DX.data.utils.compileGetter(expr),
                                        model = e.args[0].model;
                                    return getter(model)
                                };
                            var evaluate = args.evaluate || defaultEvaluate;
                            uri = uriTemplate.replace(/\{([^}]+)\}/g, function(entry, expr) {
                                expr = $.trim(expr);
                                if (expr.indexOf(",") > -1)
                                    expr = $.map(expr.split(","), $.trim);
                                var value = evaluate(expr);
                                if (value === undefined)
                                    value = "";
                                value = DX.framework.Route.prototype.formatSegment(value);
                                return value
                            });
                            var navigateOptions = (e.component || {}).NAME === "dxCommand" ? e.component.option() : {};
                            app.navigate(uri, navigateOptions);
                            e.handled = true
                        }}
                }
        }
    })(jQuery, DevExpress);
    /*! Module framework, file framework.application.js */
    (function($, DX) {
        var Class = DX.Class,
            BACK_COMMAND_TITLE,
            INIT_IN_PROGRESS = "InProgress",
            INIT_COMPLETE = "Inited",
            frameworkNS = DX.framework;
        DX.framework.Application = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this._options = options;
                this.namespace = options.namespace || options.ns || window;
                this._applicationMode = options.mode ? options.mode : "mobileApp";
                this.components = [];
                BACK_COMMAND_TITLE = DX.localization.localizeString("@Back");
                this.router = options.router || new DX.framework.MvcRouter;
                var navigationManagers = {
                        mobileApp: DX.framework.StackBasedNavigationManager,
                        webSite: DX.framework.HistoryBasedNavigationManager
                    };
                this.navigationManager = options.navigationManager || new navigationManagers[this._applicationMode]({keepPositionInStack: options.navigateToRootViewMode === "keepHistory"});
                this.navigationManager.navigating.add($.proxy(this._onNavigating, this));
                this.navigationManager.navigatingBack.add($.proxy(this._onNavigatingBack, this));
                this.navigationManager.navigated.add($.proxy(this._onNavigated, this));
                this.navigationManager.navigationCanceled.add($.proxy(this._onNavigationCanceled, this));
                this.stateManager = options.stateManager || new DX.framework.StateManager({storage: options.stateStorage || sessionStorage});
                this.stateManager.addStateSource(this.navigationManager);
                this.viewCache = this._createViewCache(options);
                this.commandMapping = this._createCommandMapping(options.commandMapping);
                this.createNavigation(options.navigation);
                this.beforeViewSetup = $.Callbacks();
                this.afterViewSetup = $.Callbacks();
                this.viewShowing = $.Callbacks();
                this.viewShown = $.Callbacks();
                this.viewHidden = $.Callbacks();
                this.viewDisposing = $.Callbacks();
                this.viewDisposed = $.Callbacks();
                this.navigating = $.Callbacks();
                this.navigatingBack = $.Callbacks();
                this.initialized = $.Callbacks();
                this._isNavigating = false;
                this._viewLinksHash = {};
                DX.registerActionExecutor(DX.framework.createActionExecutors(this));
                DX.overlayTargetContainer(".dx-viewport");
                this.components.push(this.router);
                this.components.push(this.navigationManager)
            },
            _createViewCache: function(options) {
                var result;
                if (options.viewCache)
                    result = options.viewCache;
                else if (options.disableViewCache)
                    result = new DX.framework.NullViewCache;
                else
                    result = new DX.framework.CapacityViewCacheDecorator({
                        size: options.viewCacheSize,
                        viewCache: new DX.framework.ViewCache
                    });
                result.viewRemoved.add($.proxy(function(e) {
                    this._releaseViewLink(e.viewInfo)
                }, this));
                return result
            },
            _createCommandMapping: function(commandMapping) {
                var result = commandMapping;
                if (!(commandMapping instanceof DX.framework.CommandMapping)) {
                    result = new DX.framework.CommandMapping;
                    result.load(DX.framework.CommandMapping.defaultMapping || {}).load(commandMapping || {})
                }
                return result
            },
            createNavigation: function(navigationConfig) {
                this.navigation = this._createNavigationCommands(navigationConfig);
                this._mapNavigationCommands(this.navigation, this.commandMapping)
            },
            _createNavigationCommands: function(commandConfig) {
                if (!commandConfig)
                    return [];
                var that = this,
                    generatedIdCount = 0;
                return $.map(commandConfig, function(item) {
                        var command;
                        if (item instanceof frameworkNS.dxCommand)
                            command = item;
                        else
                            command = new frameworkNS.dxCommand($.extend({root: true}, item));
                        if (!command.option("id"))
                            command.option("id", "navigation_" + generatedIdCount++);
                        return command
                    })
            },
            _mapNavigationCommands: function(navigationCommands, commandMapping) {
                var navigationCommandIds = $.map(navigationCommands, function(command) {
                        return command.option("id")
                    });
                commandMapping.mapCommands("global-navigation", navigationCommandIds)
            },
            _callComponentMethod: function(methodName, args) {
                var tasks = [];
                $.each(this.components, function(index, component) {
                    if (component[methodName] && $.isFunction(component[methodName])) {
                        var result = component[methodName](args);
                        if (result && result.done)
                            tasks.push(result)
                    }
                });
                return $.when.apply($, tasks)
            },
            init: function() {
                var that = this;
                that._initState = INIT_IN_PROGRESS;
                return that._callComponentMethod("init").done(function() {
                        that._initState = INIT_COMPLETE;
                        that._processEvent("initialized")
                    })
            },
            _onNavigatingBack: function(args) {
                this._processEvent("navigatingBack", args)
            },
            _onNavigating: function(args) {
                var that = this;
                if (that._isNavigating) {
                    that._pendingNavigationArgs = args;
                    args.cancel = true;
                    return
                }
                else {
                    that._isNavigating = true;
                    delete that._pendingNavigationArgs
                }
                var routeData = this.router.parse(args.uri);
                if (!routeData)
                    throw new Error(DX.utils.stringFormat("Routing rule is not found for the \"{0}\" url", args.uri));
                var uri = this.router.format(routeData);
                if (args.uri !== uri && uri) {
                    args.cancel = true;
                    DX.utils.executeAsync(function() {
                        that.navigate(uri, args.options)
                    })
                }
                else
                    that._processEvent("navigating", args)
            },
            _onNavigated: function(args) {
                var that = this,
                    direction = args.options.direction,
                    deferred = $.Deferred(),
                    viewInfo = that._acquireViewInfo(args.item, args.options);
                if (!that._isViewReadyToShow(viewInfo))
                    that._setViewLoadingState(viewInfo, direction).done(function() {
                        DX.utils.executeAsync(function() {
                            that._createViewModel(viewInfo);
                            that._createViewCommands(viewInfo);
                            deferred.resolve()
                        })
                    }).fail(function() {
                        that._isNavigating = false;
                        deferred.reject()
                    });
                else
                    deferred.resolve();
                deferred.done(function() {
                    that._highlightCurrentNavigationCommand(viewInfo);
                    that._showView(viewInfo, direction).always(function() {
                        that._isNavigating = false;
                        var pendingArgs = that._pendingNavigationArgs;
                        if (pendingArgs)
                            DX.utils.executeAsync(function() {
                                that.navigate(pendingArgs.uri, pendingArgs.options)
                            })
                    })
                })
            },
            _isViewReadyToShow: function(viewInfo) {
                return !!viewInfo.model
            },
            _onNavigationCanceled: function(args) {
                var that = this;
                if (!that._pendingNavigationArgs || that._pendingNavigationArgs.uri !== args.uri) {
                    var currentItem = that.navigationManager.currentItem();
                    if (currentItem)
                        DX.utils.executeAsync(function() {
                            var viewInfo = that._acquireViewInfo(currentItem, args.options);
                            that._highlightCurrentNavigationCommand(viewInfo)
                        });
                    that._isNavigating = false
                }
            },
            _disposeRemovedViews: function() {
                var that = this,
                    args;
                $.each(that._viewLinksHash, function(key, link) {
                    if (!link.linkCount) {
                        args = {viewInfo: link.viewInfo};
                        that._processEvent("viewDisposing", args, args.viewInfo.model);
                        that._disposeView(link.viewInfo);
                        that._processEvent("viewDisposed", args, args.viewInfo.model);
                        delete that._viewLinksHash[key]
                    }
                })
            },
            _onViewHidden: function(viewInfo) {
                var args = {viewInfo: viewInfo};
                this._processEvent("viewHidden", args, args.viewInfo.model)
            },
            _disposeView: function(viewInfo) {
                var commands = viewInfo.commands || [];
                $.each(commands, function(index, command) {
                    command._dispose()
                })
            },
            _acquireViewInfo: function(navigationItem, navigateOptions) {
                var viewInfo = this.viewCache.getView(navigationItem.key);
                if (!viewInfo) {
                    viewInfo = this._createViewInfo(navigationItem, navigateOptions);
                    this._obtainViewLink(viewInfo);
                    this.viewCache.setView(navigationItem.key, viewInfo)
                }
                return viewInfo
            },
            _processEvent: function(eventName, args, model) {
                this._callComponentMethod(eventName, args);
                if (this[eventName] && this[eventName].fire)
                    this[eventName].fire(args);
                var modelMethod = (model || {})[eventName];
                if (modelMethod)
                    modelMethod.call(model, args)
            },
            _createViewInfo: function(navigationItem, navigateOptions) {
                var uri = navigationItem.uri,
                    routeData = this.router.parse(uri);
                var viewInfo = {
                        viewName: routeData.view,
                        routeData: routeData,
                        uri: uri,
                        key: navigationItem.key,
                        canBack: this.canBack(),
                        navigateOptions: navigateOptions,
                        previousViewInfo: this._getPreviousViewInfo(navigateOptions)
                    };
                return viewInfo
            },
            _createViewModel: function(viewInfo) {
                this._processEvent("beforeViewSetup", {viewInfo: viewInfo});
                viewInfo.model = viewInfo.model || this._callViewCodeBehind(viewInfo);
                this._processEvent("afterViewSetup", {viewInfo: viewInfo})
            },
            _createViewCommands: function(viewInfo) {
                viewInfo.commands = viewInfo.model.commands || [];
                if (viewInfo.canBack && this._applicationMode !== "webSite")
                    this._appendBackCommand(viewInfo)
            },
            _callViewCodeBehind: function(viewInfo) {
                var setupFunc = $.noop,
                    routeData = viewInfo.routeData;
                if (routeData.view in this.namespace)
                    setupFunc = this.namespace[routeData.view];
                return setupFunc.call(this.namespace, routeData, viewInfo) || {}
            },
            _appendBackCommand: function(viewInfo) {
                var commands = viewInfo.commands,
                    that = this,
                    stackKey = this.navigationManager.currentStackKey,
                    backTitle = BACK_COMMAND_TITLE;
                if (that._options.useViewTitleAsBackText)
                    backTitle = ((viewInfo.previousViewInfo || {}).model || {}).title || backTitle;
                var toMergeTo = [new DX.framework.dxCommand({
                            id: "back",
                            title: backTitle,
                            behavior: "back",
                            action: function() {
                                that.back({stack: stackKey})
                            },
                            icon: "arrowleft",
                            type: "back"
                        })];
                var result = DX.framework.utils.mergeCommands(toMergeTo, commands);
                commands.length = 0;
                commands.push.apply(commands, result)
            },
            _showView: function(viewInfo, direction) {
                var that = this;
                var eventArgs = {
                        viewInfo: viewInfo,
                        direction: direction
                    };
                that._processEvent("viewShowing", eventArgs, viewInfo.model);
                return that._showViewImpl(eventArgs.viewInfo, eventArgs.direction).done(function() {
                        DX.utils.executeAsync(function() {
                            that._processEvent("viewShown", eventArgs, viewInfo.model);
                            that._disposeRemovedViews()
                        })
                    })
            },
            _highlightCurrentNavigationCommand: function(viewInfo) {
                var that = this,
                    selectedCommand,
                    currentUri = viewInfo.uri,
                    currentNavigationItemId = viewInfo.model && viewInfo.model.currentNavigationItemId;
                if (currentNavigationItemId !== undefined)
                    $.each(this.navigation, function(index, command) {
                        if (command.option("id") === currentNavigationItemId) {
                            selectedCommand = command;
                            return false
                        }
                    });
                if (!selectedCommand)
                    $.each(this.navigation, function(index, command) {
                        var commandUri = command.option("action");
                        if (DX.utils.isString(commandUri)) {
                            commandUri = commandUri.replace(/^#+/, "");
                            if (commandUri === that.navigationManager.rootUri()) {
                                selectedCommand = command;
                                return false
                            }
                        }
                    });
                $.each(this.navigation, function(index, command) {
                    if (command === selectedCommand && command.option("highlighted"))
                        command.optionChanged.fireWith(command, ["highlighted", true, true]);
                    command.option("highlighted", command === selectedCommand)
                })
            },
            _setViewLoadingState: DX.abstract,
            _showViewImpl: DX.abstract,
            _obtainViewLink: function(viewInfo) {
                var key = viewInfo.key;
                if (!this._viewLinksHash[key])
                    this._viewLinksHash[key] = {
                        viewInfo: viewInfo,
                        linkCount: 1
                    };
                else
                    this._viewLinksHash[key].linkCount++
            },
            _releaseViewLink: function(viewInfo) {
                if (this._viewLinksHash[viewInfo.key] === undefined)
                    DX.utils.logger.warn("A view with the '" + viewInfo.key + "' key doesn't exist");
                if (this._viewLinksHash[viewInfo.key].linkCount === 0)
                    DX.utils.logger.warn("A view with the '" + viewInfo.key + "' key has already been released");
                this._viewLinksHash[viewInfo.key].linkCount--
            },
            navigate: function(uri, options) {
                var that = this;
                if ($.isPlainObject(uri)) {
                    uri = that.router.format(uri);
                    if (uri === false)
                        throw new Error("The passed object cannot be formatted into a uri string by router. An appropriate route should be registered.");
                }
                if (!that._initState)
                    that.init().done(function() {
                        that.restoreState();
                        that.navigate(uri, options)
                    });
                else if (that._initState === INIT_COMPLETE)
                    that.navigationManager.navigate(uri, options);
                else
                    throw new Error("Unable to navigate. Application is being initialized. Consider using the 'HtmlApplication.navigating' event to alter the navigation logic.");
            },
            canBack: function(stackKey) {
                return this.navigationManager.canBack(stackKey)
            },
            _getPreviousViewInfo: function(navigateOptions) {
                var previousNavigationItem = this.navigationManager.previousItem(navigateOptions.stack),
                    result;
                if (previousNavigationItem)
                    result = this.viewCache.getView(previousNavigationItem.key);
                return result
            },
            back: function(options) {
                this.navigationManager.back(options)
            },
            saveState: function() {
                this.stateManager.saveState()
            },
            restoreState: function() {
                this.stateManager.restoreState()
            },
            clearState: function() {
                this.stateManager.clearState()
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.html.js */
    (function($, DX, undefined) {
        DX.framework.html = {
            layoutControllers: [],
            layoutSets: {}
        }
    })(jQuery, DevExpress);
    /*! Module framework, file framework.widgetCommandAdapters.js */
    (function($, DX) {
        var commandToContainer = DX.framework.utils.commandToContainer,
            DX_COMMAND_TO_WIDGET_ADAPTER = "dxCommandToWidgetAdapter";
        var WidgetItemWrapperBase = DX.Class.inherit({
                ctor: function(command, containerOptions) {
                    this.command = command;
                    this.containerOptions = containerOptions;
                    this._createWidgetItem(command, containerOptions);
                    this._commandChangedHandler = $.proxy(this._onCommandChanged, this);
                    command.optionChanged.add(this._commandChangedHandler)
                },
                _createWidgetItem: function(command, containerOptions) {
                    this.widgetItem = $.extend({
                        command: command,
                        containerOptions: containerOptions
                    }, containerOptions, command.option());
                    this._updateItem()
                },
                _onCommandChanged: function(optionName, newValue, oldValue) {
                    this.widgetItem[optionName] = newValue;
                    this._updateItem(optionName, newValue, oldValue)
                },
                _updateItem: function(optionName, newValue, oldValue){},
                dispose: function() {
                    if (this.command)
                        this.command.optionChanged.remove(this._commandChangedHandler);
                    delete this.command;
                    delete this.containerOptions;
                    delete this.widgetItem;
                    delete this.updateItemHandler
                }
            });
        var WidgetAdapterBase = DX.Class.inherit({
                ctor: function($widgetElement) {
                    this.$widgetElement = $widgetElement;
                    this.$widgetElement.data(DX_COMMAND_TO_WIDGET_ADAPTER, this);
                    this.widget = this._getWidgetByElement($widgetElement);
                    this._widgetDisposingHandler = $.proxy(this._onWidgetDisposing, this);
                    this.widget.disposing.add(this._widgetDisposingHandler);
                    this.itemWrappers = []
                },
                addCommand: function(command, containerOptions) {
                    var itemWrapper = this._createItemWrapper(command, containerOptions);
                    this.itemWrappers.push(itemWrapper);
                    this._addItemToWidget(itemWrapper);
                    this.refresh();
                    this._commandChangedHandler = $.proxy(this._onCommandChanged, this);
                    itemWrapper.command.optionChanged.add(this._commandChangedHandler)
                },
                beginUpdate: function() {
                    this.widget.beginUpdate()
                },
                endUpdate: function() {
                    this.widget.endUpdate()
                },
                _onWidgetDisposing: function() {
                    this.dispose(true)
                },
                _onCommandChanged: function(optionName, newValue, oldValue) {
                    if (name !== "highlighted")
                        this.refresh()
                },
                _addItemToWidget: function(itemWrapper) {
                    var items = this.widget.option("items");
                    items.push(itemWrapper.widgetItem)
                },
                refresh: function() {
                    var items = this.widget.option("items");
                    this.widget.option("items", items)
                },
                clear: function(widgetDisposing) {
                    var that = this;
                    $.each(that.itemWrappers, function(index, itemWrapper) {
                        itemWrapper.command.optionChanged.remove(that._commandChangedHandler);
                        itemWrapper.dispose()
                    });
                    this.itemWrappers.length = 0;
                    if (!widgetDisposing)
                        this._clearWidgetItems()
                },
                _clearWidgetItems: function() {
                    this.widget.option("items", [])
                },
                dispose: function(widgetDisposing) {
                    this.clear(widgetDisposing);
                    if (this.widget) {
                        this.widget.disposing.remove(this._widgetDisposingHandler);
                        this.$widgetElement.removeData(DX_COMMAND_TO_WIDGET_ADAPTER);
                        delete this.widget;
                        delete this.$widgetElement
                    }
                }
            });
        var CommandToWidgetAdapter = DX.Class.inherit({
                ctor: function(createAdapter) {
                    this.createAdapter = createAdapter
                },
                _getWidgetAdapter: function($container) {
                    var widgetAdapter = $container.data(DX_COMMAND_TO_WIDGET_ADAPTER);
                    if (!widgetAdapter)
                        widgetAdapter = this.createAdapter($container);
                    return widgetAdapter
                },
                addCommand: function($container, command, containerOptions) {
                    var widgetAdapter = this._getWidgetAdapter($container);
                    widgetAdapter.addCommand(command, containerOptions)
                },
                clearContainer: function($container) {
                    var widgetAdapter = this._getWidgetAdapter($container);
                    widgetAdapter.clear()
                },
                beginUpdate: function($container) {
                    var widgetAdapter = this._getWidgetAdapter($container);
                    widgetAdapter.beginUpdate()
                },
                endUpdate: function($container) {
                    var widgetAdapter = this._getWidgetAdapter($container);
                    widgetAdapter.endUpdate()
                }
            });
        var dxToolbarItemWrapper = WidgetItemWrapperBase.inherit({_updateItem: function() {
                    var widgetItem = this.widgetItem,
                        command = this.command,
                        containerOptions = this.containerOptions,
                        location = commandToContainer.resolvePropertyValue(command, containerOptions, "location");
                    widgetItem.location = location;
                    if (location === "menu")
                        widgetItem.text = commandToContainer.resolveTextValue(command, containerOptions);
                    else {
                        var options = {
                                text: commandToContainer.resolveTextValue(command, containerOptions),
                                disabled: command.option("disabled"),
                                icon: commandToContainer.resolveIconValue(command, containerOptions, "icon"),
                                iconSrc: commandToContainer.resolveIconValue(command, containerOptions, "iconSrc"),
                                type: commandToContainer.resolveTypeValue(command, containerOptions)
                            };
                        widgetItem.options = options;
                        widgetItem.widget = "button"
                    }
                }});
        var dxToolbarAdapter = WidgetAdapterBase.inherit({
                ctor: function($widgetElement) {
                    this.callBase($widgetElement);
                    this.widget.option("itemClickAction", $.proxy(this._onToolbarItemClick, this))
                },
                _onToolbarItemClick: function(e) {
                    if (e.itemData.command)
                        e.itemData.command.execute()
                },
                _getWidgetByElement: function($element) {
                    return $element.dxToolbar("instance")
                },
                _createItemWrapper: function(command, containerOptions) {
                    return new dxToolbarItemWrapper(command, containerOptions)
                },
                addCommand: function(command, containerOptions) {
                    this.callBase(command, containerOptions);
                    this.widget.option("visible", true)
                }
            });
        var dxActionSheetItemWrapper = WidgetItemWrapperBase.inherit({_updateItem: function() {
                    var widgetItem = this.widgetItem,
                        command = this.command,
                        containerOptions = this.containerOptions;
                    widgetItem.text = commandToContainer.resolveTextValue(command, containerOptions);
                    widgetItem.icon = commandToContainer.resolveIconValue(command, containerOptions, "icon");
                    widgetItem.iconSrc = commandToContainer.resolveIconValue(command, containerOptions, "iconSrc")
                }});
        var dxActionSheetAdapter = WidgetAdapterBase.inherit({
                _createItemWrapper: function(command, containerOptions) {
                    return new dxActionSheetItemWrapper(command, containerOptions)
                },
                _getWidgetByElement: function($element) {
                    return $element.dxActionSheet("instance")
                }
            });
        var dxListItemWrapper = WidgetItemWrapperBase.inherit({
                _createWidgetItem: function(command, containerOptions) {
                    this.callBase(command, containerOptions);
                    this.widgetItem.clickAction = $.proxy(this._itemClick, this)
                },
                _updateItem: function() {
                    var widgetItem = this.widgetItem,
                        command = this.command,
                        containerOptions = this.containerOptions;
                    widgetItem.title = commandToContainer.resolveTextValue(command, containerOptions);
                    widgetItem.icon = commandToContainer.resolveIconValue(command, containerOptions, "icon");
                    widgetItem.iconSrc = commandToContainer.resolveIconValue(command, containerOptions, "iconSrc")
                },
                _itemClick: function() {
                    if (!this.widgetItem.disabled)
                        this.command.execute()
                }
            });
        var dxListAdapter = WidgetAdapterBase.inherit({
                _createItemWrapper: function(command, containerOptions) {
                    return new dxListItemWrapper(command, containerOptions)
                },
                _getWidgetByElement: function($element) {
                    return $element.dxList("instance")
                }
            });
        var dxNavBarItemWrapper = WidgetItemWrapperBase.inherit({_updateItem: function(optionName, newValue, oldValue) {
                    var command = this.command,
                        containerOptions = this.containerOptions;
                    if (optionName !== "highlighted") {
                        this.widgetItem.text = commandToContainer.resolveTextValue(command, containerOptions);
                        this.widgetItem.icon = commandToContainer.resolveIconValue(command, containerOptions, "icon");
                        this.widgetItem.iconSrc = commandToContainer.resolveIconValue(command, containerOptions, "iconSrc")
                    }
                }});
        var dxNavBarAdapter = WidgetAdapterBase.inherit({
                ctor: function($widgetElement) {
                    this.callBase($widgetElement);
                    this.widget.option("itemClickAction", $.proxy(this._onNavBarItemClick, this))
                },
                _onNavBarItemClick: function(e) {
                    var items = this.widget.option("items");
                    for (var i = items.length; --i; )
                        items[i].command.option("highlighted", false);
                    e.itemData.command.execute()
                },
                _getWidgetByElement: function($element) {
                    return $element.dxNavBar("instance")
                },
                _createItemWrapper: function(command, containerOptions) {
                    return new dxNavBarItemWrapper(command, containerOptions)
                },
                addCommand: function(command, containerOptions) {
                    this.callBase(command, containerOptions);
                    this._updateSelectedIndex()
                },
                _onCommandChanged: function(name, newValue, oldValue) {
                    if (name !== "highlighted" || newValue)
                        this._updateSelectedIndex();
                    this.callBase(name, newValue, oldValue)
                },
                _updateSelectedIndex: function() {
                    var items = this.widget.option("items");
                    for (var i = 0, itemsCount = items.length; i < itemsCount; i++)
                        if (items[i].highlighted) {
                            this.widget.option("selectedIndex", i);
                            break
                        }
                }
            });
        var dxPivotItemWrapper = WidgetItemWrapperBase.inherit({_updateItem: function(optionName, newValue, oldValue) {
                    if (optionName === "title")
                        this.widgetItem.title = commandToContainer.resolveTextValue(this.command, this.containerOptions)
                }});
        var dxPivotAdapter = WidgetAdapterBase.inherit({
                ctor: function($widgetElement) {
                    this.callBase($widgetElement);
                    this._highlighting = false;
                    this.widget.option("itemSelectAction", $.proxy(this._onPivotItemSelect, this))
                },
                _onPivotItemSelect: function(e) {
                    if (e.itemData && e.itemData.command)
                        e.itemData.command.execute()
                },
                _getWidgetByElement: function($element) {
                    return $element.dxPivot("instance")
                },
                _createItemWrapper: function(command, containerOptions) {
                    return new dxToolbarItemWrapper(command, containerOptions)
                },
                addCommand: function(command, containerOptions) {
                    this.callBase(command, containerOptions);
                    this._updateSelectedIndex()
                },
                _onCommandChanged: function(optionName, newValue, oldValue) {
                    if (optionName === "visible")
                        this._rerenderPivot();
                    else if (optionName !== "highlighted" || newValue)
                        this._updateSelectedIndex()
                },
                _addItemToWidget: function(itemWrapper) {
                    if (itemWrapper.command.option("visible"))
                        this.callBase(itemWrapper)
                },
                _updateSelectedIndex: function() {
                    var pivot = this.widget,
                        items = pivot.option("items") || [];
                    DX.fx.off = true;
                    for (var i = 0, itemsCount = items.length; i < itemsCount; i++)
                        if (items[i].highlighted) {
                            if (this._highlighting && pivot.option("selectedIndex") === i)
                                this._highlighting = false;
                            pivot.option("selectedIndex", i);
                            break
                        }
                    DX.fx.off = false
                },
                _rerenderPivot: function() {
                    var that = this;
                    that.widget.option("items", []);
                    $.each(that.itemWrappers, function(index, itemWrapper) {
                        if (itemWrapper.command.option("visible"))
                            that._addItemToWidget(itemWrapper)
                    });
                    that.refresh();
                    that._updateSelectedIndex()
                }
            });
        var dxSlideOutItemWrapper = WidgetItemWrapperBase.inherit({_updateItem: function(optionName, newValue, oldValue) {
                    var widgetItem = this.widgetItem,
                        command = this.command,
                        containerOptions = this.containerOptions;
                    if (name !== "highlighted") {
                        widgetItem.title = commandToContainer.resolveTextValue(command, containerOptions);
                        widgetItem.icon = commandToContainer.resolveIconValue(command, containerOptions, "icon");
                        widgetItem.iconSrc = commandToContainer.resolveIconValue(command, containerOptions, "iconSrc")
                    }
                }});
        var dxSlideOutAdapter = WidgetAdapterBase.inherit({
                ctor: function($widgetElement) {
                    this.callBase($widgetElement);
                    this.widget.option("itemClickAction", $.proxy(this._onSlideOutItemClick, this))
                },
                _onSlideOutItemClick: function(e) {
                    e.itemData.command.execute()
                },
                _getWidgetByElement: function($element) {
                    return $element.dxSlideOut("instance")
                },
                _createItemWrapper: function(command, containerOptions) {
                    return new dxSlideOutItemWrapper(command, containerOptions)
                },
                _updateSelectedIndex: function() {
                    var items = this.widget.option("items") || [];
                    for (var i = 0, itemsCount = items.length; i < itemsCount; i++)
                        if (items[i].highlighted) {
                            this.widget.option("selectedIndex", i);
                            break
                        }
                },
                addCommand: function(command, containerOptions) {
                    this.callBase(command, containerOptions);
                    this._updateSelectedIndex()
                },
                _onCommandChanged: function(name, newValue, oldValue) {
                    if (name !== "highlighted" || newValue)
                        this._updateSelectedIndex();
                    this.callBase(name, newValue, oldValue)
                }
            });
        var adapters = DX.framework.html.commandToDXWidgetAdapters = {};
        adapters.dxToolbar = new CommandToWidgetAdapter(function($widgetElement) {
            return new dxToolbarAdapter($widgetElement)
        });
        adapters.dxActionSheet = new CommandToWidgetAdapter(function($widgetElement) {
            return new dxActionSheetAdapter($widgetElement)
        });
        adapters.dxList = new CommandToWidgetAdapter(function($widgetElement) {
            return new dxListAdapter($widgetElement)
        });
        adapters.dxNavBar = new CommandToWidgetAdapter(function($widgetElement) {
            return new dxNavBarAdapter($widgetElement)
        });
        adapters.dxPivot = new CommandToWidgetAdapter(function($widgetElement) {
            return new dxPivotAdapter($widgetElement)
        });
        adapters.dxSlideOut = new CommandToWidgetAdapter(function($widgetElement) {
            return new dxSlideOutAdapter($widgetElement)
        });
        DX.framework.html.WidgetItemWrapperBase = WidgetItemWrapperBase;
        DX.framework.html.WidgetAdapterBase = WidgetAdapterBase
    })(jQuery, DevExpress);
    /*! Module framework, file framework.commandManager.js */
    (function($, DX, undefined) {
        var Class = DX.Class,
            ui = DevExpress.ui;
        DX.framework.dxCommandContainer = DX.DOMComponent.inherit({
            ctor: function(element, options) {
                if ($.isPlainObject(element)) {
                    options = element;
                    element = $("<div />")
                }
                this.callBase(element, options)
            },
            _setDefaultOptions: function() {
                this.callBase();
                this.option({id: null})
            },
            _render: function() {
                this.callBase();
                this._element().addClass("dx-command-container")
            }
        });
        DX.registerComponent("dxCommandContainer", DX.framework.dxCommandContainer);
        DX.framework.html.CommandManager = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this.defaultWidgetAdapter = options.defaultWidgetAdapter || this._getDefaultWidgetAdapter();
                this.commandMapping = options.commandMapping || new DX.framework.CommandMapping
            },
            _getDefaultWidgetAdapter: function() {
                return {
                        addCommand: this._defaultAddCommand,
                        clearContainer: $.noop
                    }
            },
            _getContainerAdapter: function($container) {
                var componentNames = $container.data("dxComponents"),
                    adapters = DX.framework.html.commandToDXWidgetAdapters;
                if (componentNames)
                    for (var index in componentNames) {
                        var widgetName = componentNames[index];
                        if (widgetName in adapters)
                            return adapters[widgetName]
                    }
                return this.defaultWidgetAdapter
            },
            findCommands: function($view) {
                var result = $.map($view.addBack().find(".dx-command"), function(element) {
                        return $(element).dxCommand("instance")
                    });
                return result
            },
            findCommandContainers: function($markup) {
                var result = $.map($markup.find(".dx-command-container"), function(element) {
                        return $(element).dxCommandContainer("instance")
                    });
                return result
            },
            _checkCommandId: function(id, command) {
                if (id === null)
                    throw new Error("The command's 'id' option should be specified.\r\nProcessed markup: " + command._element().get(0).outerHTML);
            },
            renderCommandsToContainers: function(commands, containers) {
                var that = this,
                    commandHash = {},
                    commandIds = [];
                $.each(commands, function(i, command) {
                    var id = command.option("id");
                    that._checkCommandId(id, command);
                    commandIds.push(id);
                    commandHash[id] = command
                });
                that.commandMapping.checkCommandsExist(commandIds);
                $.each(containers, function(k, container) {
                    var commandInfos = [];
                    $.each(commandHash, function(id, command) {
                        var commandId = id;
                        var commandOptions = that.commandMapping.getCommandMappingForContainer(commandId, container.option("id"));
                        if (commandOptions)
                            commandInfos.push({
                                command: command,
                                options: commandOptions
                            })
                    });
                    if (commandInfos.length)
                        that._attachCommandsToContainer(container._element(), commandInfos)
                })
            },
            clearContainer: function(container) {
                var $container = container._element(),
                    adapter = this._getContainerAdapter($container);
                adapter.clearContainer($container)
            },
            _arrangeCommandsToContainers: function(commands, containers) {
                DX.utils.logger.warn("The _arrangeCommandsToContainers function is deprecated. Use renderCommandsToContainers instead");
                this.renderCommandsToContainers(commands, containers)
            },
            _attachCommandsToContainer: function($container, commandInfos) {
                var adapter = this._getContainerAdapter($container);
                if (adapter.beginUpdate)
                    adapter.beginUpdate($container);
                $.each(commandInfos, function(index, commandInfo) {
                    adapter.addCommand($container, commandInfo.command, commandInfo.options)
                });
                if (adapter.endUpdate)
                    adapter.endUpdate($container);
                return true
            },
            _defaultAddCommand: function($container, command, options) {
                var $source = command._element();
                if ($source) {
                    $container.append($source);
                    $source.on("dxclick", function() {
                        command.execute()
                    })
                }
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.layoutController.js */
    (function($, DX, undefined) {
        var Class = DX.Class;
        var HIDDEN_BAG_ID = "__hidden-bag";
        var TRANSITION_SELECTOR = ".dx-transition:not(.dx-transition .dx-transition)";
        var transitionSelector = function(transitionName) {
                return ".dx-transition-" + transitionName
            };
        DX.framework.html.DefaultLayoutController = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this.name = options.layoutTemplateName || options.name || "";
                this._disableViewLoadingState = options.disableViewLoadingState;
                this._layoutModel = options.layoutModel || {};
                this._defaultPaneName = options.defaultPaneName || "content";
                this.viewReleased = $.Callbacks();
                this.viewRendered = $.Callbacks()
            },
            init: function(options) {
                options = options || {};
                this._visibleViews = {};
                this._$viewPort = options.$viewPort || $("body");
                this._$hiddenBag = options.$hiddenBag || $(document.getElementById(HIDDEN_BAG_ID)) || $("<div/>").hide().appendTo("body");
                this._commandManager = options.commandManager;
                this._viewEngine = options.viewEngine;
                this._prepareTemplates();
                this.DEFAULT_LOADING_TITLE = DX.localization.localizeString("@Loading");
                if (options.templateContext) {
                    this._templateContextChanged = options.templateContext.optionChanged;
                    this._proxiedTemplateContextChangedHandler = $.proxy(this._templateContextChangedHandler, this)
                }
            },
            activate: function() {
                var $rootElement = this._getRootElement();
                this._justActivated = true;
                $rootElement.show();
                this._moveToViewPort($rootElement);
                this._attachRefreshViewRequiredHandler()
            },
            deactivate: function() {
                this._releaseVisibleViews();
                this._moveToHiddenBag(this._getRootElement());
                this._detachRefreshViewRequiredHandler()
            },
            _releaseVisibleViews: function() {
                var that = this;
                $.each(this._visibleViews, function(index, viewInfo) {
                    that._hideView(viewInfo);
                    that._releaseView(viewInfo)
                });
                this._visibleViews = {}
            },
            _templateContextChangedHandler: function() {
                $.each(this._visibleViews, $.proxy(function(index, viewInfo) {
                    this.showView(viewInfo)
                }, this))
            },
            _attachRefreshViewRequiredHandler: function() {
                if (this._templateContextChanged)
                    this._templateContextChanged.add(this._proxiedTemplateContextChangedHandler)
            },
            _detachRefreshViewRequiredHandler: function() {
                if (this._templateContextChanged)
                    this._templateContextChanged.remove(this._proxiedTemplateContextChangedHandler)
            },
            _getPreviousViewInfo: function(viewInfo) {
                return this._visibleViews[this._getViewPaneName(viewInfo.viewTemplateInfo)]
            },
            _prepareTemplates: function() {
                var that = this;
                var $layoutTemplate = that._viewEngine.findLayoutTemplate(this._getLayoutTemplateName()).removeClass("dx-hidden");
                that._$layoutTemplate = $layoutTemplate;
                that._$mainLayout = that._createEmptyLayout().show();
                that._viewEngine._applyTemplate(that._$mainLayout, that._layoutModel);
                that._$navigationWidget = that._createNavigationWidget();
                that._loadingStateViewInfo = that._createLoadingStateViewInfo($layoutTemplate)
            },
            renderNavigation: function(navigationCommands) {
                this._clearNavigationWidget();
                this._renderNavigationImpl(navigationCommands)
            },
            _renderNavigationImpl: function(navigationCommands) {
                this._renderCommands(this._$mainLayout, navigationCommands)
            },
            _createNavigationWidget: function() {
                var result;
                this._$mainLayout.find(".dx-command-container").each(function() {
                    var container = $(this).dxCommandContainer("instance");
                    if (container.option("id") === "global-navigation")
                        result = $(this)
                });
                return result
            },
            _clearNavigationWidget: function() {
                if (this._$navigationWidget)
                    this._commandManager.clearContainer(this._$navigationWidget.dxCommandContainer("instance"))
            },
            _getRootElement: function() {
                return this._$mainLayout
            },
            _getViewFrame: function(viewInfo) {
                return this._$mainLayout
            },
            _getLayoutTemplateName: function() {
                return this.name
            },
            _applyModelToTransitionElements: function($markup, model) {
                var that = this;
                this._getTransitionElements($markup).each(function(i, item) {
                    that._viewEngine._applyTemplate($(item).children(), model)
                })
            },
            _createLoadingStateViewInfo: function($layoutTemplate) {
                var $loadingStateView = $layoutTemplate.clone().addClass("dx-loading-state-view").appendTo(this._$hiddenBag),
                    model = {title: ko.observable()};
                this._viewEngine._createComponents($loadingStateView);
                this._applyModelToTransitionElements($loadingStateView, model);
                var result = {
                        model: model,
                        renderResult: {
                            $markup: $loadingStateView,
                            $viewItems: $()
                        },
                        isLoadingStateView: true
                    };
                this._appendViewToLayout(result);
                return result
            },
            _createViewLayoutTemplate: function() {
                var that = this;
                var $viewLayoutTemplate = that._$layoutTemplate.clone().appendTo(that._$hiddenBag);
                that._viewEngine._createComponents($viewLayoutTemplate);
                return $viewLayoutTemplate
            },
            _createEmptyLayout: function() {
                var that = this;
                var $result = that._$layoutTemplate.clone().appendTo(that._$hiddenBag);
                that._viewEngine._createComponents($result);
                that._removeTransitionContent($result);
                return $result
            },
            _removeTransitionContent: function($markup) {
                var $transitionElements = this._getTransitionElements($markup);
                $transitionElements.children().remove()
            },
            _getTransitionElements: function($markup) {
                return $markup.find(TRANSITION_SELECTOR).addBack(TRANSITION_SELECTOR)
            },
            setViewLoadingState: function(viewInfo, direction) {
                var that = this;
                if (that._disableViewLoadingState)
                    return $.Deferred().resolve().promise();
                var loadingStateViewInfo = $.extend({}, viewInfo, that._loadingStateViewInfo);
                that._loadingStateViewInfo.model.title((viewInfo.viewTemplateInfo || {}).title || this.DEFAULT_LOADING_TITLE);
                return that._showViewImpl(loadingStateViewInfo, direction)
            },
            showView: function(viewInfo, direction) {
                var that = this;
                var previousViewInfo = that._getPreviousViewInfo(viewInfo);
                if (previousViewInfo && previousViewInfo.isLoadingStateView)
                    direction = "none";
                that._ensureViewRendered(viewInfo);
                return this._showViewImpl(viewInfo, direction).done(function() {
                        that._onViewShown(viewInfo)
                    })
            },
            disposeView: function(viewInfo) {
                this._clearRenderResult(viewInfo)
            },
            _clearRenderResult: function(viewInfo) {
                if (viewInfo.renderResult) {
                    viewInfo.renderResult.$markup.remove();
                    viewInfo.renderResult.$viewItems.remove();
                    delete viewInfo.renderResult
                }
            },
            _prepareViewTemplate: function($viewTemplate, viewInfo) {
                this._viewEngine._createComponents($viewTemplate)
            },
            _renderViewImpl: function($viewTemplate, viewInfo) {
                var that = this,
                    $layout = this._createViewLayoutTemplate(),
                    $viewItems = $viewTemplate.children(),
                    isSimplifiedMarkup = true,
                    outOfContentItems = $();
                this._applyModelToTransitionElements($layout, viewInfo.model);
                this._viewEngine._applyLayoutCore($viewTemplate, $layout);
                $viewItems.each(function(i, item) {
                    var $item = $(item);
                    that._viewEngine._applyTemplate($item, viewInfo.model);
                    if ($item.is(".dx-command,.dx-content,script"))
                        isSimplifiedMarkup = false;
                    else
                        outOfContentItems = outOfContentItems.add($item)
                });
                if (outOfContentItems.length && !isSimplifiedMarkup)
                    throw new Error("All the dxView element children should be either of the dxCommand or dxContent type.\r\nProcessed markup: " + outOfContentItems[0].outerHTML);
                viewInfo.renderResult = viewInfo.renderResult || {};
                viewInfo.renderResult.$viewItems = $viewItems;
                viewInfo.renderResult.$markup = $layout
            },
            _renderCommands: function($markup, commands) {
                var commandContainers = this._findCommandContainers($markup);
                this._commandManager.renderCommandsToContainers(commands, commandContainers)
            },
            _applyViewCommands: function(viewInfo) {
                var $viewItems = viewInfo.renderResult.$viewItems,
                    $markup = viewInfo.renderResult.$markup,
                    viewCommands = this._commandManager.findCommands($viewItems);
                viewInfo.commands = DX.framework.utils.mergeCommands(viewInfo.commands || [], viewCommands);
                this._renderCommands($markup, viewInfo.commands)
            },
            _findCommandContainers: function($markup) {
                return this._viewEngine._createComponents($markup, ["dxCommandContainer"])
            },
            _ensureViewRendered: function(viewInfo) {
                var viewTemplateInstance = viewInfo.$viewTemplate ? viewInfo.$viewTemplate.dxView("instance") : this._viewEngine.findViewComponent(viewInfo.viewName),
                    currentViewId = viewTemplateInstance.getId(),
                    $cachedMarkup = viewInfo.renderResult && viewInfo.renderResult.markupCache[currentViewId];
                if ($cachedMarkup)
                    viewInfo.renderResult.$markup = $cachedMarkup;
                else {
                    this._renderView(viewInfo);
                    viewInfo.renderResult.markupCache = viewInfo.renderResult.markupCache || {};
                    viewInfo.renderResult.markupCache[currentViewId] = viewInfo.renderResult.$markup
                }
            },
            _renderView: function(viewInfo) {
                var $viewTemplate = viewInfo.$viewTemplate || this._viewEngine.findViewTemplate(viewInfo.viewName);
                this._prepareViewTemplate($viewTemplate, viewInfo);
                this._renderViewImpl($viewTemplate, viewInfo);
                this._applyViewCommands(viewInfo);
                this._appendViewToLayout(viewInfo);
                $viewTemplate.remove();
                this._onRenderComplete(viewInfo);
                this.viewRendered.fire(viewInfo)
            },
            _appendViewToLayout: function(viewInfo) {
                var that = this,
                    $viewFrame = that._getViewFrame(viewInfo),
                    $markup = viewInfo.renderResult.$markup,
                    $transitionContentElements = $();
                $.each($markup.find(".dx-content-placeholder"), function(index, el) {
                    var placeholder = $(el).dxContentPlaceholder("instance");
                    placeholder.prepareTransition()
                });
                $.each(that._getTransitionElements($viewFrame), function(index, transitionElement) {
                    var $transition = $(transitionElement),
                        $viewElement = $markup.find(transitionSelector($transition.data("dx-transition-name"))).children();
                    that._hideViewElements($viewElement);
                    $transition.append($viewElement);
                    $transitionContentElements = $transitionContentElements.add($viewElement)
                });
                that._$mainLayout.append(viewInfo.renderResult.$viewItems.filter(".dx-command"));
                $markup.remove();
                viewInfo.renderResult.$markup = $transitionContentElements
            },
            _onRenderComplete: function(){},
            _onViewShown: function(viewInfo) {
                $(document).trigger("dx.viewchanged")
            },
            _doTransition: function(viewInfo, direction) {
                var that = this,
                    deferred = $.Deferred();
                var transitions = $.map(viewInfo.renderResult.$markup, function(transitionContent) {
                        var $transitionContent = $(transitionContent),
                            $transition = $transitionContent.parent(),
                            transitionType = that._disableTransitions ? "none" : $transition.data("dx-transition-type");
                        return {
                                destination: $transition,
                                source: $transitionContent,
                                type: transitionType || "none",
                                direction: direction || "none"
                            }
                    });
                that._executeTransitions(transitions).done(function() {
                    deferred.resolve()
                });
                return deferred.promise()
            },
            _hideView: function(viewInfo) {
                if (viewInfo.renderResult)
                    this._hideViewElements(viewInfo.renderResult.$markup)
            },
            _showViewImpl: function(viewInfo, direction) {
                var that = this,
                    deferred = $.Deferred();
                if (this._justActivated) {
                    this._justActivated = false;
                    direction = "none"
                }
                return that._doTransition(viewInfo, direction).done(function() {
                        that._changeView(viewInfo)
                    })
            },
            _releaseView: function(viewInfo) {
                this.viewReleased.fireWith(this, [viewInfo])
            },
            _getViewPortElement: function() {
                return this._$viewPort
            },
            _getHiddenBagElement: function() {
                return this._$hiddenBag
            },
            _changeView: function(viewInfo) {
                var that = this;
                var previousViewInfo = that._getPreviousViewInfo(viewInfo);
                if (previousViewInfo && previousViewInfo !== viewInfo) {
                    that._hideView(previousViewInfo);
                    if (!previousViewInfo.isLoadingStateView)
                        this._releaseView(previousViewInfo)
                }
                this._visibleViews[this._getViewPaneName(viewInfo.viewTemplateInfo)] = viewInfo
            },
            _getViewPaneName: function(viewTemplateInfo) {
                return this._defaultPaneName
            },
            _hideViewElements: function($elements) {
                DX.utils.triggerHidingEvent($elements.filter(".dx-active-view"));
                this._patchIDs($elements);
                this._disableInputs($elements);
                $elements.removeClass("dx-active-view").addClass("dx-inactive-view")
            },
            _showViewElements: function($elements) {
                this._unpatchIDs($elements);
                this._enableInputs($elements);
                $elements.removeClass("dx-inactive-view").addClass("dx-active-view");
                DX.utils.triggerShownEvent($elements.filter(".dx-active-view"))
            },
            _executeTransitions: function(transitions) {
                var that = this;
                var animatedTransitions = $.map(transitions, function(transitionOptions) {
                        that._showViewElements(transitionOptions.source);
                        if (transitionOptions.source.children().length)
                            return DX.framework.html.TransitionExecutor.create(transitionOptions.destination, transitionOptions)
                    });
                var animatedDeferreds = $.map(animatedTransitions, function(transition) {
                        transition.options.source.addClass("dx-transition-source");
                        return transition.exec()
                    });
                var result = $.when.apply($, animatedDeferreds).done(function() {
                        $.each(animatedTransitions, function(index, transition) {
                            transition.finalize();
                            that._hideViewElements(transition.options.source.parent().find(".dx-active-view:not(.dx-transition-source)"));
                            transition.options.source.removeClass("dx-transition-source")
                        })
                    });
                return result
            },
            _patchIDs: function($markup) {
                this._processIDs($markup, function(id) {
                    var result = id;
                    if (id.indexOf(HIDDEN_BAG_ID) === -1)
                        result = HIDDEN_BAG_ID + "-" + id;
                    return result
                })
            },
            _unpatchIDs: function($markup) {
                this._processIDs($markup, function(id) {
                    var result = id;
                    if (id.indexOf(HIDDEN_BAG_ID) === 0)
                        result = id.substr(HIDDEN_BAG_ID.length + 1);
                    return result
                })
            },
            _processIDs: function($markup, process) {
                var elementsWithIds = $markup.find("[id]");
                $.each(elementsWithIds, function(index, element) {
                    var $el = $(element),
                        id = $el.attr("id");
                    $el.attr("id", process(id))
                })
            },
            _enableInputs: function($markup) {
                var $inputs = $markup.find(":input[data-disabled=true]");
                $.each($inputs, function(index, input) {
                    $(input).removeAttr("disabled").removeAttr("data-disabled")
                })
            },
            _disableInputs: function($markup) {
                var $inputs = $markup.find(":input:not([disabled], [disabled=true])");
                $.each($inputs, function(index, input) {
                    $(input).attr({
                        disabled: true,
                        "data-disabled": true
                    })
                })
            },
            _moveToViewPort: function($items) {
                $items.appendTo(this._getViewPortElement());
                $items.find(".dx-visibility-change-handler").each(function() {
                    $(this).triggerHandler("dxshown")
                })
            },
            _moveToHiddenBag: function($items) {
                $items.appendTo(this._getHiddenBagElement())
            }
        });
        var layoutSets = DX.framework.html.layoutSets;
        layoutSets["default"] = layoutSets["default"] || [];
        layoutSets["default"].push({controller: new DX.framework.html.DefaultLayoutController})
    })(jQuery, DevExpress);
    /*! Module framework, file framework.templateEngine.js */
    (function($, DX, undefined) {
        var Class = DX.Class;
        DX.framework.html.KnockoutJSTemplateEngine = Class.inherit({applyTemplate: function(template, model) {
                ko.applyBindings(model, $(template).get(0))
            }})
    })(jQuery, DevExpress);
    /*! Module framework, file framework.viewEngine.js */
    (function($, DX, undefined) {
        var Class = DX.Class,
            ui = DX.ui,
            _VIEW_ROLE = "dxView",
            _LAYOUT_ROLE = "dxLayout",
            lastViewId = 0;
        DX.framework[_VIEW_ROLE] = DX.DOMComponent.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    name: null,
                    title: null,
                    layout: null
                })
            },
            ctor: function() {
                this.callBase.apply(this, arguments);
                this._id = ++lastViewId
            },
            _render: function() {
                this.callBase();
                this._element().addClass("dx-view")
            },
            getId: function() {
                return this._id
            }
        });
        DX.registerComponent(_VIEW_ROLE, DX.framework.dxView);
        DX.framework[_LAYOUT_ROLE] = DX.DOMComponent.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({name: null})
            },
            _render: function() {
                this.callBase();
                this._element().addClass("dx-layout")
            }
        });
        DX.registerComponent(_LAYOUT_ROLE, DX.framework.dxLayout);
        DX.framework.dxViewPlaceholder = DX.DOMComponent.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({viewName: null})
            },
            _render: function() {
                this.callBase();
                this._element().addClass("dx-view-placeholder")
            }
        });
        DX.registerComponent("dxViewPlaceholder", DX.framework.dxViewPlaceholder);
        var setupTransitionElement = function($element, transitionType, transitionName, contentCssPosition) {
                if (contentCssPosition === "absolute")
                    $element.addClass("dx-transition-absolute");
                else
                    $element.addClass("dx-transition-static");
                $element.addClass("dx-transition").addClass("dx-transition-" + transitionName);
                $element.data("dx-transition-type", transitionType);
                $element.data("dx-transition-name", transitionName)
            };
        var setupTransitionInnerElement = function($element) {
                $element.addClass("dx-transition-inner-wrapper")
            };
        DX.framework.dxTransition = DX.DOMComponent.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    name: null,
                    type: "slide"
                })
            },
            _render: function() {
                this.callBase();
                var element = this._element();
                setupTransitionElement(element, this.option("type"), this.option("name"), "absolute");
                element.wrapInner("<div/>");
                setupTransitionInnerElement(element.children())
            },
            _clean: function() {
                this.callBase();
                this._element().empty()
            }
        });
        DX.registerComponent("dxTransition", DX.framework.dxTransition);
        DX.framework.dxContentPlaceholder = DX.DOMComponent.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({
                    name: null,
                    transition: "none",
                    contentCssPosition: "absolute"
                })
            },
            _render: function() {
                this.callBase();
                var $element = this._element();
                $element.addClass("dx-content-placeholder").addClass("dx-content-placeholder-" + this.option("name"));
                setupTransitionElement($element, this.option("transition"), this.option("name"), this.option("contentCssPosition"))
            },
            prepareTransition: function() {
                var $element = this._element();
                if ($element.children(".dx-content").length === 0) {
                    $element.wrapInner("<div>");
                    $element.children().dxContent({targetPlaceholder: this.option("name")})
                }
            }
        });
        DX.registerComponent("dxContentPlaceholder", DX.framework.dxContentPlaceholder);
        DX.framework.dxContent = DX.DOMComponent.inherit({
            _setDefaultOptions: function() {
                this.callBase();
                this.option({targetPlaceholder: null})
            },
            _optionChanged: function(name) {
                this._refresh()
            },
            _clean: function() {
                this.callBase();
                this._element().removeClass(this._currentClass)
            },
            _render: function() {
                this.callBase();
                var element = this._element();
                element.addClass("dx-content");
                this._currentClass = "dx-content-" + this.option("targetPlaceholder");
                element.addClass(this._currentClass);
                setupTransitionInnerElement(element)
            }
        });
        DX.registerComponent("dxContent", DX.framework.dxContent);
        DX.framework.html.ViewEngine = Class.inherit({
            ctor: function(options) {
                options = options || {};
                this.$root = options.$root;
                this.device = options.device || {};
                this.templateEngine = options.templateEngine;
                this.dataOptionsAttributeName = options.dataOptionsAttributeName || "data-options";
                this._templateMap = {};
                this._pendingViewContainer = null;
                this.viewSelecting = $.Callbacks();
                this.modelFromViewDataExtended = $.Callbacks();
                this.layoutSelecting = $.Callbacks();
                this._templateContext = options.templateContext
            },
            init: function() {
                var that = this;
                this._initDefaultLayout();
                return this._loadExternalTemplates().done(function() {
                        that._loadTemplatesFromMarkupCore(that.$root.children());
                        that._processTemplates()
                    })
            },
            _enumerateTemplates: function(processFn) {
                var that = this;
                $.each(that._templateMap, function(name, templatesByRoleMap) {
                    $.each(templatesByRoleMap, function(role, templates) {
                        $.each(templates, function(index, template) {
                            processFn(template)
                        })
                    })
                })
            },
            _findComponent: function(name, role) {
                var components = (this._templateMap[name] || {})[role] || [],
                    filter = this._templateContext && this._templateContext.option() || {};
                components = this._filterTemplates(filter, components);
                this._checkMatchedTemplates(components);
                return components[0]
            },
            _findTemplate: function(name, role) {
                var component = this._findComponent(name, role);
                if (!component)
                    throw new Error("Error 404: Template not found. role:  " + role + ", name: " + name);
                var $template = component._element(),
                    $result = $template.clone();
                this._createComponents($result, [role]);
                return $result
            },
            _extendModelFromViewData: function($view, model) {
                DX.utils.extendFromObject(model, $view.data(_VIEW_ROLE).option());
                this.modelFromViewDataExtended.fire({
                    view: $view,
                    model: model
                })
            },
            _createComponents: function($markup, types) {
                var that = this;
                var result = [];
                $markup.find("*").addBack().filter("[" + that.dataOptionsAttributeName + "]").each(function(index, element) {
                    var $element = $(element),
                        optionsString = $element.attr(that.dataOptionsAttributeName),
                        options;
                    try {
                        options = new Function("return {" + optionsString + "}")()
                    }
                    catch(ex) {
                        throw new Error(DX.utils.stringFormat("Unable to parse options.\nMessage: {0};\nOptions value: {1}", ex, optionsString));
                    }
                    for (var componentName in options)
                        if (!types || $.inArray(componentName, types) > -1)
                            if ($element[componentName]) {
                                $element[componentName](options[componentName]);
                                result.push($element[componentName]("instance"))
                            }
                });
                return result
            },
            _loadTemplatesFromMarkupCore: function($markup) {
                if ($markup.find("[data-dx-role]").length)
                    throw Error("View templates should be updated according to the 13.1 changes. Go to http://dxpr.es/15ikrJA for more details");
                var that = this;
                $markup.appendTo(this.$root);
                DX.localization.localizeNode($markup);
                var components = that._createComponents($markup, [_VIEW_ROLE, _LAYOUT_ROLE]);
                $.each(components, function(index, component) {
                    var $element = component._element();
                    $element.addClass("dx-hidden");
                    that._registerTemplateComponent(component);
                    component._element().detach()
                })
            },
            _registerTemplateComponent: function(component) {
                var role = component.NAME,
                    options = component.option(),
                    templateName = options.name,
                    componentsByRoleMap = this._templateMap[templateName] || {};
                componentsByRoleMap[role] = componentsByRoleMap[role] || [];
                componentsByRoleMap[role].push(component);
                this._templateMap[templateName] = componentsByRoleMap
            },
            _applyPartialViews: function($render) {
                var that = this;
                this._createComponents($render, ["dxViewPlaceholder"]);
                $.each($render.find(".dx-view-placeholder"), function() {
                    var $partialPlaceholder = $(this);
                    var viewName = $partialPlaceholder.data("dxViewPlaceholder").option("viewName");
                    var $view = that._findTemplate(viewName, _VIEW_ROLE);
                    that._applyPartialViews($view);
                    $partialPlaceholder.append($view);
                    $view.removeClass("dx-hidden")
                })
            },
            _ajaxImpl: function() {
                return $.ajax.apply($, arguments)
            },
            _loadTemplatesFromURL: function(url) {
                var that = this,
                    options = this._getLoadOptions(),
                    deferred = $.Deferred();
                this._ajaxImpl({
                    url: options.winPhonePrefix + url,
                    isLocal: options.isLocal,
                    dataType: "html"
                }).done(function(data) {
                    that._loadTemplatesFromMarkupCore(DX.utils.createMarkupFromString(data));
                    deferred.resolve()
                });
                return deferred.promise()
            },
            _getLoadOptions: function() {
                if (location.protocol.indexOf("wmapp") >= 0)
                    return {
                            winPhonePrefix: location.protocol + "www/",
                            isLocal: true
                        };
                return {
                        winPhonePrefix: "",
                        isLocal: undefined
                    }
            },
            _loadExternalTemplates: function() {
                var tasks = [],
                    that = this;
                $("head").find("link[rel='dx-template']").each(function(index, link) {
                    var task = that._loadTemplatesFromURL($(link).attr("href"));
                    tasks.push(task)
                });
                return $.when.apply($, tasks)
            },
            _processTemplates: function() {
                var that = this;
                $.each(that._templateMap, function(name, templatesByRoleMap) {
                    $.each(templatesByRoleMap, function(role, templates) {
                        that._filterTemplatesByDevice(templates)
                    })
                });
                that._enumerateTemplates(function(template) {
                    that._applyPartialViews(template._element())
                })
            },
            _filterTemplatesByDevice: function(components) {
                var filteredComponents = this._filterTemplates(this.device, components);
                $.each(components, function(index, component) {
                    if ($.inArray(component, filteredComponents) < 0) {
                        component._dispose();
                        component._element().remove()
                    }
                });
                components.length = 0;
                components.push.apply(components, filteredComponents)
            },
            _filterTemplates: function(filter, components) {
                return DX.utils.findBestMatches(filter, components, function(component) {
                        return component.option()
                    })
            },
            _checkMatchedTemplates: function(bestMatches) {
                if (bestMatches.length > 1) {
                    var message = "Concurrent templates are found:\r\n";
                    $.each(bestMatches, function(index, match) {
                        message += match._element().attr("data-options") + "\r\n"
                    });
                    message += "Target device:\r\n";
                    message += JSON.stringify(this.device);
                    throw Error(message);
                }
            },
            _extendModelFormViewTemplate: function($viewTemplate, model) {
                this._extendModelFromViewData($viewTemplate, model)
            },
            _ensureTemplates: function(viewInfo) {
                this._ensureViewTemplate(viewInfo)
            },
            _ensureViewTemplate: function(viewInfo) {
                viewInfo.$viewTemplate = viewInfo.$viewTemplate || this.findViewTemplate(viewInfo.viewName);
                return viewInfo.$viewTemplate
            },
            _wrapViewDefaultContent: function($viewTemplate) {
                $viewTemplate.wrapInner("<div class=\"dx-full-height\"></div>");
                $viewTemplate.children().eq(0).dxContent({targetPlaceholder: 'content'})
            },
            _initDefaultLayout: function() {
                this._$defaultLayoutTemplate = $("<div class=\"dx-full-height\" data-options=\"dxLayout : { name: 'default' } \"> \
                <div class=\"dx-full-height\" data-options=\"dxContentPlaceholder : { name: 'content' } \" ></div> \
            </div>")
            },
            _getDefaultLayoutTemplate: function() {
                var $result = this._$defaultLayoutTemplate.clone();
                this._createComponents($result);
                return $result
            },
            _applyTemplate: function($markup, model) {
                var that = this;
                $markup.each(function(i, element) {
                    that.templateEngine.applyTemplate(element, model)
                })
            },
            _applyLayoutCore: function($view, $layout) {
                if ($layout === undefined || $layout.length === 0)
                    $layout = this._getDefaultLayoutTemplate();
                if ($view.children(".dx-content").length === 0)
                    this._wrapViewDefaultContent($view);
                var $toMerge = $().add($layout).add($view);
                var $placeholderContents = $toMerge.find(".dx-content");
                $.each($placeholderContents, function() {
                    var $placeholderContent = $(this);
                    var placeholderId = $placeholderContent.data("dxContent").option("targetPlaceholder");
                    var $placeholder = $toMerge.find(".dx-content-placeholder-" + placeholderId);
                    $placeholder.empty();
                    $placeholder.append($placeholderContent)
                });
                $placeholderContents.filter(":not(.dx-content-placeholder .dx-content)").remove();
                return $layout
            },
            findViewTemplate: function(viewName) {
                var findViewEventArgs = {viewName: viewName};
                this.viewSelecting.fire(findViewEventArgs);
                return findViewEventArgs.view ? $(findViewEventArgs.view) : this._findTemplate(viewName, _VIEW_ROLE, true)
            },
            findViewComponent: function(name) {
                return this._findComponent(name, "dxView")
            },
            findLayoutTemplate: function(layoutName) {
                if (!layoutName)
                    return this._getDefaultLayoutTemplate();
                var findLayoutEventArgs = {layoutName: layoutName};
                this.layoutSelecting.fire(findLayoutEventArgs);
                return findLayoutEventArgs.layout ? $(findLayoutEventArgs.layout) : this._findTemplate(layoutName, _LAYOUT_ROLE)
            },
            loadTemplates: function(source) {
                var result;
                if (typeof source === "string")
                    result = this._loadTemplatesFromURL(source);
                else {
                    this._loadTemplatesFromMarkupCore(source);
                    result = $.Deferred().resolve().promise()
                }
                return result.done($.proxy(this._processTemplates, this))
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.htmlApplication.js */
    (function($, DX, undefined) {
        var frameworkNS = DX.framework,
            htmlNS = frameworkNS.html;
        var VIEW_PORT_CLASSNAME = "dx-viewport";
        var HIDDEN_BAG_ID = "__hidden-bag";
        var HIDDEN_BAG_CLASSNAME = "dx-hidden-bag";
        htmlNS.HtmlApplication = frameworkNS.Application.inherit({
            ctor: function(options) {
                options = options || {};
                this.callBase(options);
                this._$root = $(options.rootNode || document.body);
                this._initViewport(options.viewPort);
                if (this._applicationMode === "mobileApp")
                    DX.utils.initMobileViewport(options);
                this.device = options.device || DX.devices.current();
                var layoutSets = DX.framework.html.layoutSets;
                this.commandManager = options.commandManager || new DX.framework.html.CommandManager({commandMapping: this.commandMapping});
                $.each(options.layoutControllers || DX.framework.html.layoutControllers, function(_, layoutControllerInfo) {
                    var targetLayoutSet = layoutControllerInfo.navigationType;
                    layoutSets[targetLayoutSet] = layoutSets[targetLayoutSet] || [];
                    layoutSets[targetLayoutSet].push(layoutControllerInfo);
                    delete layoutControllerInfo.navigationType
                });
                if (options.navigationType)
                    DX.utils.logger.warn("The 'navigationType' option is deprecated, use 'layoutSet' instead");
                if (options.defaultLayout)
                    DX.utils.logger.warn("The 'defaultLayout' option is deprecated, use 'layoutSet' instead");
                var navigationType = options.navigationType || options.defaultLayout;
                if (navigationType)
                    options.layoutSet = layoutSets[navigationType];
                this._initHiddenBag();
                this._initTemplateContext();
                this.viewEngine = options.viewEngine || new htmlNS.ViewEngine({
                    $root: this._$root,
                    device: this.device,
                    templateEngine: options.templateEngine || new htmlNS.KnockoutJSTemplateEngine({navigationManager: this.navigationManager}),
                    templateContext: this._templateContext
                });
                this.components.push(this.viewEngine);
                this.viewRendered = $.Callbacks();
                this._layoutSet = options.layoutSet || (options.layoutControllers && options.layoutControllers.length ? options.layoutControllers : layoutSets["default"]);
                this._availableLayoutControllers = [];
                this.resolveLayoutController = $.Callbacks()
            },
            _createViewCache: function(options) {
                var result = this.callBase(options);
                if (!options.viewCache)
                    result = new DX.framework.ConditionalViewCacheDecorator({
                        filter: function(key, viewInfo) {
                            return !viewInfo.viewTemplateInfo.disableCache
                        },
                        viewCache: result
                    });
                return result
            },
            _initViewport: function() {
                this._$viewPort = this._getViewPort();
                DX.ui.themes.attachCssClasses(this._$viewPort);
                DX.devices.attachCssClasses(this._$viewPort)
            },
            _getViewPort: function() {
                var $viewPort = $("." + VIEW_PORT_CLASSNAME);
                if (!$viewPort.length)
                    $viewPort = $("<div>").addClass(VIEW_PORT_CLASSNAME).appendTo(this._$root);
                return $viewPort
            },
            _initHiddenBag: function() {
                this._$hiddenBag = this._getHiddenBag(this._$root, this._$viewPort)
            },
            _getHiddenBag: function($root, $viewPort) {
                var $hiddenBag = $("#" + HIDDEN_BAG_ID);
                if (!$hiddenBag.length)
                    $hiddenBag = $("<div/>").addClass(HIDDEN_BAG_CLASSNAME).attr("id", HIDDEN_BAG_ID).appendTo($root);
                $hiddenBag.addClass(($viewPort.attr("class") || "").replace(VIEW_PORT_CLASSNAME, ""));
                return $hiddenBag
            },
            _initTemplateContext: function() {
                this._templateContext = new DX.Component({orientation: DX.devices.orientation()});
                DX.devices.orientationChanged.add($.proxy(function(args) {
                    this._templateContext.option("orientation", args.orientation)
                }, this))
            },
            _showViewImpl: function(viewInfo, direction) {
                this._activateLayoutController(viewInfo.layoutController);
                this._obtainViewLink(viewInfo);
                return this._activeLayoutController.showView(viewInfo, direction)
            },
            _setViewLoadingState: function(viewInfo, direction) {
                this._activateLayoutController(viewInfo.layoutController);
                return this._activeLayoutController.setViewLoadingState(viewInfo, direction)
            },
            _resolveLayoutController: function(viewInfo) {
                var args = {
                        viewInfo: viewInfo,
                        layoutController: null,
                        availableLayoutControllers: this._availableLayoutControllers
                    };
                this._processEvent("resolveLayoutController", args, viewInfo.model);
                return args.layoutController || this._resolveLayoutControllerImpl(viewInfo)
            },
            _resolveLayoutControllerImpl: function(viewInfo) {
                var target = $.extend({
                        root: !viewInfo.canBack,
                        customResolveRequired: false,
                        pane: (viewInfo.viewTemplateInfo || {}).pane
                    }, DX.devices.current());
                var matches = DX.utils.findBestMatches(target, this._availableLayoutControllers);
                if (!matches.length)
                    throw Error("The layout controller cannot be resolved. There are no appropriate layout controllers for the current context. Make sure you have the corresponding *.js references in your main *.html file.");
                if (matches.length > 1)
                    throw Error("The layout controller cannot be resolved. Two or more layout controllers suit the current context. Make the layout controllers registration more specific.");
                return matches[0].controller
            },
            _activateLayoutController: function(layoutController) {
                var that = this;
                if (that._activeLayoutController !== layoutController) {
                    if (that._activeLayoutController)
                        that._activeLayoutController.deactivate();
                    layoutController.activate();
                    that._activeLayoutController = layoutController
                }
            },
            init: function() {
                var that = this,
                    result = this.callBase();
                result.done(function() {
                    that._initLayoutControllers();
                    that.renderNavigation()
                });
                return result
            },
            _disposeView: function(viewInfo) {
                if (viewInfo.layoutController.disposeView)
                    viewInfo.layoutController.disposeView(viewInfo);
                this.callBase(viewInfo)
            },
            viewPort: function() {
                return this._$viewPort
            },
            _createViewInfo: function(navigationItem, navigateOptions) {
                var viewInfo = this.callBase.apply(this, arguments),
                    templateInfo = this.getViewTemplateInfo(viewInfo.viewName);
                if (!templateInfo)
                    throw new Error("The '" + viewInfo.viewName + "' view template is not found. Make sure case is correct and the template fits the current context.");
                viewInfo.viewTemplateInfo = templateInfo;
                viewInfo.layoutController = this._resolveLayoutController(viewInfo);
                return viewInfo
            },
            _createViewModel: function(viewInfo) {
                this.callBase(viewInfo);
                var templateInfo = viewInfo.viewTemplateInfo,
                    model = viewInfo.model;
                for (var name in templateInfo)
                    if (!(name in model))
                        model[name] = templateInfo[name]
            },
            _initLayoutControllers: function() {
                var that = this;
                $.each(that._layoutSet, function(index, controllerInfo) {
                    var controller = controllerInfo.controller,
                        target = DX.devices.current();
                    if (DX.utils.findBestMatches(target, [controllerInfo]).length) {
                        that._availableLayoutControllers.push(controllerInfo);
                        if (controller.init)
                            controller.init({
                                app: that,
                                $viewPort: that._$viewPort,
                                $hiddenBag: that._$hiddenBag,
                                navigationManager: that.navigationManager,
                                viewEngine: that.viewEngine,
                                templateContext: that._templateContext,
                                commandManager: that.commandManager
                            });
                        if (controller.viewReleased)
                            controller.viewReleased.add(function(viewInfo) {
                                that._onViewReleased(viewInfo)
                            });
                        if (controller.viewRendered)
                            controller.viewRendered.add(function(viewInfo) {
                                that._processEvent("viewRendered", {viewInfo: viewInfo}, viewInfo.model)
                            })
                    }
                })
            },
            _onViewReleased: function(viewInfo) {
                this._onViewHidden(viewInfo);
                this._releaseViewLink(viewInfo)
            },
            renderNavigation: function() {
                var that = this;
                $.each(that._availableLayoutControllers, function(index, controllerInfo) {
                    var controller = controllerInfo.controller;
                    if (controller.renderNavigation)
                        controller.renderNavigation(that.navigation)
                })
            },
            getViewTemplate: function(viewName) {
                return this.viewEngine.findViewTemplate(viewName)
            },
            getViewTemplateInfo: function(viewName) {
                var viewComponent = this.viewEngine.findViewComponent(viewName);
                return viewComponent && viewComponent.option()
            },
            loadTemplates: function(source) {
                return this.viewEngine.loadTemplates(source)
            },
            templateContext: function() {
                return this._templateContext
            }
        })
    })(jQuery, DevExpress);
    /*! Module framework, file framework.transitionExecutor.js */
    (function($, DX) {
        $.fn.extend({unwrapInner: function(selector) {
                return this.each(function() {
                        var t = this,
                            c = $(t).children(selector);
                        c.each(function() {
                            var e = $(this);
                            e.contents().appendTo(t);
                            e.remove()
                        })
                    })
            }});
        var TRANSITION_DURATION = 400;
        var TransitionExecutor = DX.Class.inherit({
                ctor: function(container, options) {
                    this.container = container;
                    this.options = options
                },
                exec: function() {
                    var that = this,
                        options = that.options;
                    var $source = options.source,
                        $destination = options.destination;
                    var $sourceAbsoluteWrapper = $source,
                        $destinationRelativeWrapper = $destination,
                        $destinationAbsoluteWrapper = that._getTransitionInnerElement($destination);
                    this._finalize = function(){};
                    return that._animate($.extend({}, options, {
                            source: $sourceAbsoluteWrapper,
                            destination: $destinationAbsoluteWrapper
                        }))
                },
                finalize: function() {
                    if (!this._finalize)
                        throw Error("The \"exec\" method should be called before the \"finalize\" one");
                    this._finalize()
                },
                _getTransitionInnerElement: function($transitionElement) {
                    return $transitionElement.children(".dx-active-view:not(.dx-transition-source)")
                },
                _animate: function() {
                    return (new $.Deferred).resolve().promise()
                }
            });
        var NoneTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
                    var $source = options.source,
                        $destination = options.destination;
                    var containerWidth = this.container.width();
                    DX.fx.animate($source, {
                        type: "slide",
                        from: {left: 0},
                        to: {left: 0},
                        duration: 0
                    });
                    DX.fx.animate($destination, {
                        type: "slide",
                        from: {left: -containerWidth},
                        to: {left: -containerWidth},
                        duration: 0
                    });
                    return $.Deferred().resolve().promise()
                }});
        var SlideTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
                    if (options.direction === "none")
                        return $.Deferred().resolve().promise();
                    var $source = options.source,
                        $destination = options.destination;
                    var directionModifier = options.direction === "backward" ? -1 : 1,
                        rtlModifier = DX.rtlEnabled ? -1 : 1,
                        containerWidth = this.container.width() * directionModifier * rtlModifier;
                    var promiseSource = DX.fx.animate($source, {
                            type: "slide",
                            from: {left: containerWidth},
                            to: {left: 0},
                            duration: TRANSITION_DURATION
                        });
                    var promiseDestination = DX.fx.animate($destination, {
                            type: "slide",
                            from: {left: 0},
                            to: {left: -containerWidth},
                            duration: TRANSITION_DURATION
                        });
                    return $.when(promiseDestination, promiseSource)
                }});
        var SlideIOS7TransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
                    if (options.direction === "none")
                        return $.Deferred().resolve().promise();
                    var $source = options.source,
                        $destination = options.destination;
                    var rtlModifier = DX.rtlEnabled ? -1 : 1,
                        containerWidth = this.container.width() * rtlModifier,
                        slowTransitionWidth = containerWidth / 5,
                        sourceLeftFrom,
                        sourceLeftTo,
                        destinationLeftFrom,
                        destinationLeftTo,
                        sourceZIndex = $source.css("z-index"),
                        destinationZIndex = $destination.css("z-index");
                    if (options.direction === "backward") {
                        sourceLeftFrom = -slowTransitionWidth;
                        sourceLeftTo = 0;
                        destinationLeftFrom = 0;
                        destinationLeftTo = containerWidth;
                        $source.css("z-index", 1);
                        $destination.css("z-index", 2)
                    }
                    else {
                        sourceLeftFrom = containerWidth;
                        sourceLeftTo = 0;
                        destinationLeftFrom = 0;
                        destinationLeftTo = -slowTransitionWidth;
                        $source.css("z-index", 2);
                        $destination.css("z-index", 1)
                    }
                    var promiseSource = DX.fx.animate($source, {
                            type: "slide",
                            from: {left: sourceLeftFrom},
                            to: {left: sourceLeftTo},
                            duration: TRANSITION_DURATION
                        });
                    var promiseDestination = DX.fx.animate($destination, {
                            type: "slide",
                            from: {left: destinationLeftFrom},
                            to: {left: destinationLeftTo},
                            duration: TRANSITION_DURATION
                        });
                    return $.when(promiseDestination, promiseSource).done(function() {
                            $source.css("z-index", sourceZIndex);
                            $destination.css("z-index", destinationZIndex)
                        })
                }});
        var OverflowTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
                    var $source = options.source,
                        $destination = options.destination,
                        destinationTop = $destination.position().top,
                        destinationLeft = $destination.position().left,
                        containerWidth = this.container.width();
                    if (options.direction === "backward")
                        containerWidth = -containerWidth;
                    var animations = [];
                    if (options.direction === "forward")
                        animations.push(DX.fx.animate($source, {
                            type: "slide",
                            from: {
                                top: destinationTop,
                                left: containerWidth + destinationLeft,
                                "z-index": 1
                            },
                            to: {left: destinationLeft},
                            duration: TRANSITION_DURATION
                        }));
                    else {
                        animations.push(DX.fx.animate($source, {
                            type: "slide",
                            from: {
                                left: destinationLeft,
                                "z-index": 1
                            },
                            to: {left: destinationLeft},
                            duration: TRANSITION_DURATION
                        }));
                        animations.push(DX.fx.animate($destination, {
                            type: "slide",
                            from: {"z-index": 2},
                            to: {left: destinationLeft - containerWidth},
                            duration: TRANSITION_DURATION
                        }))
                    }
                    return $.when.apply($, animations)
                }});
        var FadeTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
                    var $source = options.source,
                        $destination = options.destination,
                        d = new $.Deferred;
                    $source.css({opacity: 0});
                    $destination.animate({opacity: 0}, TRANSITION_DURATION);
                    $source.animate({opacity: 1}, TRANSITION_DURATION, function() {
                        d.resolve()
                    });
                    return d.promise()
                }});
        var transitionType = function(options) {
                if (options.type === "fade")
                    return options.type;
                if (options.direction === "none")
                    return "none";
                return options.type
            };
        TransitionExecutor.create = function(container, options) {
            var device = DX.devices.current();
            switch (transitionType(options)) {
                case"none":
                    return new NoneTransitionExecutor(container, options);
                case"slide":
                    if (device.platform === "ios" && device.version[0] === 7)
                        return new SlideIOS7TransitionExecutor(container, options);
                    else
                        return new SlideTransitionExecutor(container, options);
                case"fade":
                    return new FadeTransitionExecutor(container, options);
                case"overflow":
                    return new OverflowTransitionExecutor(container, options);
                default:
                    throw Error(DX.utils.formatString("Unknown transition type \"{0}\"", options.type));
            }
        };
        DX.framework.html.TransitionExecutor = TransitionExecutor;
        DX.framework.html.NoneTransitionExecutor = NoneTransitionExecutor;
        DX.framework.html.SlideIOS7TransitionExecutor = SlideIOS7TransitionExecutor;
        DX.framework.html.SlideTransitionExecutor = SlideTransitionExecutor;
        DX.framework.html.OverflowTransitionExecutor = OverflowTransitionExecutor;
        DX.framework.html.FadeTransitionExecutor = FadeTransitionExecutor
    })(jQuery, DevExpress);
    DevExpress.MOD_FRAMEWORK = true
}
